<?php

declare(strict_types=1);

namespace app\admin\controller\crud;

use Throwable;
use ba\Exception as BaException;
use ba\Filesystem;
use ba\TableManager;
use app\admin\model\CrudLog;
use app\admin\model\AdminLog;
use app\admin\model\AdminRule;
use app\common\controller\Backend;
use app\common\library\Menu;
use app\admin\library\crud\Helper;
use Webman\Http\Request;
use support\Response;
use support\think\Db;

/**
 * CRUD 代码生成器（Webman 迁移版）
 */
class Crud extends Backend
{
    protected array $modelData = [];
    protected array $controllerData = [];
    protected array $indexVueData = [];
    protected array $formVueData = [];
    protected string $webTranslate = '';
    protected array $langTsData = [];
    protected array $dtStringToArray = ['checkbox', 'selects', 'remoteSelects', 'city', 'images', 'files'];
    protected array $noNeedPermission = ['logStart', 'getFileData', 'parseFieldData', 'generateCheck', 'uploadCompleted'];

    protected function initController(Request $request): ?Response
    {
        return null;
    }

    public function generate(Request $request): Response
    {
        $response = $this->initializeBackend($request);
        if ($response !== null) return $response;

        $type = $request->post('type', '');
        $table = $request->post('table', []);
        $fields = $request->post('fields', []);

        if (!$table || !$fields || !isset($table['name']) || !$table['name']) {
            return $this->error(__('Parameter error'));
        }

        $crudLogId = 0;
        try {
            $crudLogId = Helper::recordCrudStatus([
                'table' => $table,
                'fields' => $fields,
                'status' => 'start',
            ]);

            $tableName = TableManager::tableName($table['name'], false, $table['databaseConnection'] ?? null);

            if ($type == 'create' || ($table['rebuild'] ?? '') == 'Yes') {
                TableManager::phinxTable($tableName, [], true, $table['databaseConnection'] ?? null)->drop()->save();
            }

            [$tablePk] = Helper::handleTableDesign($table, $fields);

            $tableComment = mb_substr($table['comment'] ?? '', -1) == '表'
                ? mb_substr($table['comment'], 0, -1) . '管理'
                : ($table['comment'] ?? '');

            $modelFile = Helper::parseNameData($table['isCommonModel'] ?? false ? 'common' : 'admin', $tableName, 'model', $table['modelFile'] ?? '');
            $validateFile = Helper::parseNameData($table['isCommonModel'] ?? false ? 'common' : 'admin', $tableName, 'validate', $table['validateFile'] ?? '');
            $controllerFile = Helper::parseNameData('admin', $tableName, 'controller', $table['controllerFile'] ?? '');
            $webViewsDir = Helper::parseWebDirNameData($tableName, 'views', $table['webViewsDir'] ?? '');
            $webLangDir = Helper::parseWebDirNameData($tableName, 'lang', $table['webViewsDir'] ?? '');

            $this->webTranslate = implode('.', $webLangDir['lang']) . '.';

            $quickSearchField = $table['quickSearchField'] ?? [$tablePk];
            if (!in_array($tablePk, $quickSearchField)) {
                $quickSearchField[] = $tablePk;
            }
            $quickSearchFieldZhCnTitle = [];

            $this->modelData = [
                'append' => [], 'methods' => [], 'fieldType' => [], 'createTime' => '', 'updateTime' => '',
                'beforeInsertMixins' => [], 'beforeInsert' => '', 'afterInsert' => '',
                'connection' => $table['databaseConnection'] ?? '', 'name' => $tableName,
                'className' => $modelFile['lastName'], 'namespace' => $modelFile['namespace'],
                'relationMethodList' => [],
            ];
            $this->controllerData = [
                'use' => [], 'attr' => [], 'methods' => [], 'filterRule' => '',
                'className' => $controllerFile['lastName'], 'namespace' => $controllerFile['namespace'],
                'tableComment' => $tableComment, 'modelName' => $modelFile['lastName'],
                'modelNamespace' => $modelFile['namespace'],
            ];
            $this->indexVueData = [
                'enableDragSort' => false, 'defaultItems' => [],
                'tableColumn' => [['type' => 'selection', 'align' => 'center', 'operator' => 'false']],
                'dblClickNotEditColumn' => ['undefined'], 'optButtons' => ['edit', 'delete'],
                'defaultOrder' => '',
            ];
            $this->formVueData = ['bigDialog' => false, 'formFields' => [], 'formValidatorRules' => [], 'imports' => []];
            $this->langTsData = ['en' => [], 'zh-cn' => []];

            $fieldsMap = [];
            foreach ($fields as $field) {
                $fieldsMap[$field['name']] = $field['designType'];
                Helper::analyseField($field);
                Helper::getDictData($this->langTsData['en'], $field, 'en');
                Helper::getDictData($this->langTsData['zh-cn'], $field, 'zh-cn');

                if (in_array($field['name'], $quickSearchField)) {
                    $quickSearchFieldZhCnTitle[] = $this->langTsData['zh-cn'][$field['name']] ?? $field['name'];
                }
                if (($field['designType'] ?? '') == 'switch') {
                    $this->indexVueData['dblClickNotEditColumn'][] = $field['name'];
                }

                $columnDict = $this->getColumnDict($field);
                if (in_array($field['name'], $table['formFields'] ?? [])) {
                    $this->formVueData['formFields'][] = $this->getFormField($field, $columnDict, $table['databaseConnection'] ?? null);
                }
                if (in_array($field['name'], $table['columnFields'] ?? [])) {
                    $this->indexVueData['tableColumn'][] = $this->getTableColumn($field, $columnDict);
                }
                if (in_array($field['designType'] ?? '', ['remoteSelect', 'remoteSelects'])) {
                    $this->parseJoinData($field, $table);
                }
                $this->parseModelMethods($field, $this->modelData);
                $this->parseSundryData($field, $table);

                if (!in_array($field['name'], $table['formFields'] ?? [])) {
                    $this->controllerData['attr']['preExcludeFields'][] = $field['name'];
                }
            }

            $this->langTsData['en']['quick Search Fields'] = implode(',', $quickSearchField);
            $this->langTsData['zh-cn']['quick Search Fields'] = implode('、', $quickSearchFieldZhCnTitle);
            $this->controllerData['attr']['quickSearchField'] = $quickSearchField;

            $weighKey = array_search('weigh', $fieldsMap);
            if ($weighKey !== false) {
                $this->indexVueData['enableDragSort'] = true;
                $this->modelData['afterInsert'] = Helper::assembleStub('mixins/model/afterInsert', ['field' => $weighKey]);
            }

            $this->indexVueData['tableColumn'][] = [
                'label' => "t('Operate')", 'align' => 'center',
                'width' => $this->indexVueData['enableDragSort'] ? 140 : 100,
                'render' => 'buttons', 'buttons' => 'optButtons', 'operator' => 'false',
            ];
            if ($this->indexVueData['enableDragSort']) {
                array_unshift($this->indexVueData['optButtons'], 'weigh-sort');
            }

            Helper::writeWebLangFile($this->langTsData, $webLangDir);
            Helper::writeModelFile($tablePk, $fieldsMap, $this->modelData, $modelFile);
            Helper::writeControllerFile($this->controllerData, $controllerFile);

            $validateContent = Helper::assembleStub('mixins/validate/validate', [
                'namespace' => $validateFile['namespace'],
                'className' => $validateFile['lastName'],
            ]);
            Helper::writeFile($validateFile['parseFile'], $validateContent);

            $this->indexVueData['tablePk'] = $tablePk;
            $this->indexVueData['webTranslate'] = $this->webTranslate;
            Helper::writeIndexFile($this->indexVueData, $webViewsDir, $controllerFile);
            Helper::writeFormFile($this->formVueData, $webViewsDir, $fields, $this->webTranslate);

            Helper::createMenu($webViewsDir, $tableComment);

            Helper::recordCrudStatus(['id' => $crudLogId, 'status' => 'success']);
        } catch (BaException $e) {
            Helper::recordCrudStatus(['id' => $crudLogId ?: 0, 'status' => 'error']);
            return $this->error($e->getMessage());
        } catch (Throwable $e) {
            Helper::recordCrudStatus(['id' => $crudLogId ?: 0, 'status' => 'error']);
            if (env('app_debug', false)) throw $e;
            return $this->error($e->getMessage());
        }

        return $this->success('', ['crudLog' => CrudLog::find($crudLogId)]);
    }

    public function logStart(Request $request): Response
    {
        $response = $this->initializeBackend($request);
        if ($response !== null) return $response;

        $id = $request->post('id');
        $type = $request->post('type', '');

        if ($type == 'Cloud history') {
            try {
                $client = get_ba_client();
                $response = $client->request('GET', '/api/v6.Crud/info', [
                    'query' => [
                        'id' => $id,
                        'server' => 1,
                        'ba-user-token' => $request->post('token', ''),
                    ]
                ]);
                $content = $response->getBody()->getContents();
                $statusCode = $response->getStatusCode();
                if ($content == '' || stripos($content, '<title>系统发生错误</title>') !== false || $statusCode != 200) {
                    return $this->error(__('Failed to load cloud data'));
                }
                $json = json_decode($content, true);
                if (json_last_error() != JSON_ERROR_NONE || !is_array($json)) {
                    return $this->error(__('Failed to load cloud data'));
                }
                if (($json['code'] ?? 0) != 1) {
                    return $this->error($json['msg'] ?? __('Failed to load cloud data'));
                }
                $info = $json['data']['info'] ?? null;
            } catch (Throwable $e) {
                return $this->error(__('Failed to load cloud data'));
            }
        } else {
            $row = CrudLog::find($id);
            $info = $row ? $row->toArray() : null;
        }

        if (!$info) {
            return $this->error(__('Record not found'));
        }

        $connection = TableManager::getConnection($info['table']['databaseConnection'] ?? '');
        $tableName = TableManager::tableName($info['table']['name'], false, $connection);
        $adapter = TableManager::phinxAdapter(true, $connection);
        if ($adapter->hasTable($tableName)) {
            $info['table']['empty'] = Db::connect($connection)->name($tableName)->limit(1)->select()->isEmpty();
        } else {
            $info['table']['empty'] = true;
        }

        AdminLog::instance($request)->setTitle(__('Log start'));

        return $this->success('', [
            'table' => $info['table'],
            'fields' => $info['fields'],
            'sync' => $info['sync'] ?? 0,
        ]);
    }

    public function delete(Request $request): Response
    {
        $response = $this->initializeBackend($request);
        if ($response !== null) return $response;

        $id = $request->post('id');
        $row = CrudLog::find($id);
        if (!$row) {
            return $this->error(__('Record not found'));
        }
        $info = $row->toArray();

        $webLangDir = Helper::parseWebDirNameData($info['table']['name'], 'lang', $info['table']['webViewsDir'] ?? '');
        $files = [
            $webLangDir['en'] . '.ts',
            $webLangDir['zh-cn'] . '.ts',
            ($info['table']['webViewsDir'] ?? '') . '/index.vue',
            ($info['table']['webViewsDir'] ?? '') . '/popupForm.vue',
            $info['table']['controllerFile'] ?? '',
            $info['table']['modelFile'] ?? '',
            $info['table']['validateFile'] ?? '',
        ];
        try {
            foreach ($files as $file) {
                $file = Filesystem::fsFit(root_path() . $file);
                if (file_exists($file)) {
                    unlink($file);
                }
                Filesystem::delEmptyDir(dirname($file));
            }
            Menu::delete(Helper::getMenuName($webLangDir), true);
            Helper::recordCrudStatus(['id' => $id, 'status' => 'delete']);
        } catch (Throwable $e) {
            return $this->error($e->getMessage());
        }
        return $this->success(__('Deleted successfully'));
    }

    public function getFileData(Request $request): Response
    {
        $response = $this->initializeBackend($request);
        if ($response !== null) return $response;

        $table = $request->get('table');
        $commonModel = $request->get('commonModel', false);

        if (!$table) {
            return $this->error(__('Parameter error'));
        }

        try {
            $modelFile = Helper::parseNameData($commonModel ? 'common' : 'admin', $table, 'model');
            $validateFile = Helper::parseNameData($commonModel ? 'common' : 'admin', $table, 'validate');
            $controllerFile = Helper::parseNameData('admin', $table, 'controller');
            $webViewsDir = Helper::parseWebDirNameData($table, 'views');
        } catch (Throwable $e) {
            return $this->error($e->getMessage());
        }

        $adminModelFiles = Filesystem::getDirFiles(root_path() . 'app' . DIRECTORY_SEPARATOR . 'admin' . DIRECTORY_SEPARATOR . 'model' . DIRECTORY_SEPARATOR);
        $commonModelFiles = Filesystem::getDirFiles(root_path() . 'app' . DIRECTORY_SEPARATOR . 'common' . DIRECTORY_SEPARATOR . 'model' . DIRECTORY_SEPARATOR);
        $adminControllerFiles = get_controller_list();

        $modelFileList = [];
        $controllerFiles = [];
        foreach ($adminModelFiles as $item) {
            $item = Filesystem::fsFit('app/admin/model/' . $item);
            $modelFileList[$item] = $item;
        }
        foreach ($commonModelFiles as $item) {
            $item = Filesystem::fsFit('app/common/model/' . $item);
            $modelFileList[$item] = $item;
        }

        $outExcludeController = ['Addon.php', 'Ajax.php', 'Dashboard.php', 'Index.php', 'Module.php', 'Terminal.php', 'routine/AdminInfo.php', 'routine/Config.php'];
        foreach ($adminControllerFiles as $item) {
            if (!in_array($item, $outExcludeController)) {
                $item = Filesystem::fsFit('app/admin/controller/' . $item);
                $controllerFiles[$item] = $item;
            }
        }

        return $this->success('', [
            'modelFile' => $modelFile['rootFileName'],
            'controllerFile' => $controllerFile['rootFileName'],
            'validateFile' => $validateFile['rootFileName'],
            'controllerFileList' => $controllerFiles,
            'modelFileList' => $modelFileList,
            'webViewsDir' => $webViewsDir['views'],
        ]);
    }

    public function checkCrudLog(Request $request): Response
    {
        $response = $this->initializeBackend($request);
        if ($response !== null) return $response;

        $table = $request->get('table');
        $connection = $request->get('connection', config('thinkorm.default', config('database.default', 'mysql')));

        if (!$table) {
            return $this->error(__('Parameter error'));
        }

        $crudLog = Db::name('crud_log')
            ->where('table_name', $table)
            ->where('connection', $connection)
            ->order('create_time desc')
            ->find();

        $id = ($crudLog && isset($crudLog['status']) && $crudLog['status'] == 'success') ? $crudLog['id'] : 0;

        return $this->success('', ['id' => $id]);
    }

    public function parseFieldData(Request $request): Response
    {
        $response = $this->initializeBackend($request);
        if ($response !== null) return $response;

        AdminLog::instance($request)->setTitle(__('Parse field data'));
        $type = $request->post('type');
        $table = $request->post('table');
        $connection = TableManager::getConnection($request->post('connection', ''));
        $table = TableManager::tableName($table, true, $connection);
        $connectionConfig = TableManager::getConnectionConfig($connection);

        if ($type == 'db') {
            $sql = 'SELECT * FROM `information_schema`.`tables` WHERE TABLE_SCHEMA = ? AND table_name = ?';
            $tableInfo = Db::connect($connection)->query($sql, [$connectionConfig['database'], $table]);
            if (!$tableInfo) {
                return $this->error(__('Record not found'));
            }
            $adapter = TableManager::phinxAdapter(false, $connection);
            $empty = $adapter->hasTable($table)
                ? Db::connect($connection)->table($table)->limit(1)->select()->isEmpty()
                : true;

            return $this->success('', [
                'columns' => Helper::parseTableColumns($table, false, $connection),
                'comment' => $tableInfo[0]['TABLE_COMMENT'] ?? '',
                'empty' => $empty,
            ]);
        }
        return $this->error(__('Parameter error'));
    }

    public function generateCheck(Request $request): Response
    {
        $response = $this->initializeBackend($request);
        if ($response !== null) return $response;

        AdminLog::instance($request)->setTitle(__('Generate check'));
        $table = $request->post('table');
        $connection = $request->post('connection', '');
        $webViewsDir = $request->post('webViewsDir', '');
        $controllerFile = $request->post('controllerFile', '');

        if (!$table) {
            return $this->error(__('Parameter error'));
        }

        try {
            $webViewsDir = Helper::parseWebDirNameData($table, 'views', $webViewsDir);
            $controllerFile = Helper::parseNameData('admin', $table, 'controller', $controllerFile)['rootFileName'];
        } catch (Throwable $e) {
            return $this->error($e->getMessage());
        }

        $tableList = TableManager::getTableList($connection);
        $tableExist = array_key_exists(TableManager::tableName($table, true, $connection), $tableList);
        $controllerExist = file_exists(root_path() . $controllerFile);
        $menuName = Helper::getMenuName($webViewsDir);
        $menuExist = AdminRule::where('name', $menuName)->value('id');

        if ($controllerExist || $tableExist || $menuExist) {
            return $this->error('', [
                'menu' => $menuExist,
                'table' => $tableExist,
                'controller' => $controllerExist,
            ], -1);
        }
        return $this->success();
    }

    public function uploadCompleted(Request $request): Response
    {
        $response = $this->initializeBackend($request);
        if ($response !== null) return $response;

        $syncIds = $request->post('syncIds', []);
        $syncIds = is_array($syncIds) ? $syncIds : [];
        $cancelSync = $request->post('cancelSync', false);

        $crudLogModel = new CrudLog();

        if ($cancelSync) {
            $logData = $crudLogModel->where('id', 'in', array_keys($syncIds))->select();
            foreach ($logData as $logDatum) {
                if (isset($syncIds[$logDatum->id]) && $logDatum->sync == $syncIds[$logDatum->id]) {
                    $logDatum->sync = 0;
                    $logDatum->save();
                }
            }
            return $this->success();
        }

        foreach ($syncIds as $key => $syncId) {
            $row = $crudLogModel->find($key);
            if ($row) {
                $row->sync = $syncId;
                $row->save();
            }
        }

        return $this->success();
    }

    private function parseJoinData($field, $table): void
    {
        $dictEn = [];
        $dictZhCn = [];
        if (empty($field['form']['relation-fields']) || empty($field['form']['remote-table'])) {
            return;
        }
        $columns = Helper::parseTableColumns($field['form']['remote-table'], true, $table['databaseConnection'] ?? null);
        $relationFields = explode(',', $field['form']['relation-fields']);
        $tableName = TableManager::tableName($field['form']['remote-table'], false, $table['databaseConnection'] ?? null);
        $rnPattern = '/(.*)(_ids|_id)$/';
        $relationName = preg_match($rnPattern, $field['name'])
            ? parse_name(preg_replace($rnPattern, '$1', $field['name']), 1, false)
            : parse_name($field['name'] . '_table', 1, false);

        if (empty($field['form']['remote-model']) || !file_exists(root_path() . $field['form']['remote-model'])) {
            $joinModelFile = Helper::parseNameData('admin', $tableName, 'model', $field['form']['remote-model'] ?? '');
            if (!file_exists(root_path() . $joinModelFile['rootFileName'])) {
                $joinModelData = [
                    'append' => [], 'methods' => [], 'fieldType' => [], 'createTime' => '', 'updateTime' => '',
                    'beforeInsertMixins' => [], 'beforeInsert' => '', 'afterInsert' => '',
                    'connection' => $table['databaseConnection'] ?? '', 'name' => $tableName,
                    'className' => $joinModelFile['lastName'], 'namespace' => $joinModelFile['namespace'],
                ];
                $joinTablePk = 'id';
                $joinFieldsMap = [];
                foreach ($columns as $column) {
                    $joinFieldsMap[$column['name']] = $column['designType'];
                    $this->parseModelMethods($column, $joinModelData);
                    if ($column['primaryKey']) $joinTablePk = $column['name'];
                }
                $weighKey = array_search('weigh', $joinFieldsMap);
                if ($weighKey !== false) {
                    $joinModelData['afterInsert'] = Helper::assembleStub('mixins/model/afterInsert', ['field' => $weighKey]);
                }
                Helper::writeModelFile($joinTablePk, $joinFieldsMap, $joinModelData, $joinModelFile);
            }
            $field['form']['remote-model'] = $joinModelFile['rootFileName'];
        }

        if ($field['designType'] == 'remoteSelect') {
            $this->controllerData['attr']['withJoinTable'][$relationName] = $relationName;
            $relationData = [
                'relationMethod' => $relationName, 'relationMode' => 'belongsTo',
                'relationPrimaryKey' => $field['form']['remote-pk'] ?? 'id',
                'relationForeignKey' => $field['name'],
                'relationClassName' => str_replace(['.php', '/'], ['', '\\'], '\\' . $field['form']['remote-model']) . "::class",
            ];
            $this->modelData['relationMethodList'][$relationName] = Helper::assembleStub('mixins/model/belongsTo', $relationData);
            if ($relationFields) {
                $this->controllerData['relationVisibleFieldList'][$relationData['relationMethod']] = $relationFields;
            }
        } elseif ($field['designType'] == 'remoteSelects') {
            $this->modelData['append'][] = $relationName;
            $this->modelData['methods'][] = Helper::assembleStub('mixins/model/getters/remoteSelectLabels', [
                'field' => parse_name($relationName, 1),
                'className' => str_replace(['.php', '/'], ['', '\\'], '\\' . $field['form']['remote-model']),
                'primaryKey' => $field['form']['remote-pk'] ?? 'id',
                'foreignKey' => $field['name'],
                'labelFieldName' => $field['form']['remote-field'] ?? 'name',
            ]);
        }

        foreach ($relationFields as $relationField) {
            if (!array_key_exists($relationField, $columns)) continue;
            $relationFieldPrefix = $relationName . '.';
            $relationFieldLangPrefix = strtolower($relationName) . '__';
            Helper::getDictData($dictEn, $columns[$relationField], 'en', $relationFieldLangPrefix);
            Helper::getDictData($dictZhCn, $columns[$relationField], 'zh-cn', $relationFieldLangPrefix);

            if (($columns[$relationField]['designType'] ?? '') == 'switch') {
                $this->indexVueData['dblClickNotEditColumn'][] = $field['name'];
            }

            $columnDict = $this->getColumnDict($columns[$relationField], $relationFieldLangPrefix);
            $columns[$relationField]['designType'] = $field['designType'];
            $columns[$relationField]['form'] = ($field['form'] ?? []) + ($columns[$relationField]['form'] ?? []);
            $columns[$relationField]['table'] = ($field['table'] ?? []) + ($columns[$relationField]['table'] ?? []);

            $remoteAttr = [
                'pk' => $this->getRemoteSelectPk($field),
                'field' => $field['form']['remote-field'] ?? 'name',
                'remoteUrl' => $this->getRemoteSelectUrl($field),
            ];

            if (($columns[$relationField]['table']['comSearchRender'] ?? '') == 'remoteSelect') {
                $renderColumn = $columns[$relationField];
                $renderColumn['table']['operator'] = 'false';
                unset($renderColumn['table']['comSearchRender']);
                $this->indexVueData['tableColumn'][] = $this->getTableColumn($renderColumn, $columnDict, $relationFieldPrefix, $relationFieldLangPrefix);
                $columns[$relationField]['table']['show'] = 'false';
                $columns[$relationField]['table']['label'] = "t('" . $this->webTranslate . $relationFieldLangPrefix . $columns[$relationField]['name'] . "')";
                $columns[$relationField]['name'] = $field['name'];
                if ($field['designType'] == 'remoteSelects') {
                    $remoteAttr['multiple'] = 'true';
                }
                $columnData = $this->getTableColumn($columns[$relationField], $columnDict, '', $relationFieldLangPrefix);
                $columnData['comSearchInputAttr'] = array_merge($remoteAttr, $columnData['comSearchInputAttr'] ?? []);
            } else {
                $columnData = $this->getTableColumn($columns[$relationField], $columnDict, $relationFieldPrefix, $relationFieldLangPrefix);
            }
            $this->indexVueData['tableColumn'][] = $columnData;
        }
        $this->langTsData['en'] = array_merge($this->langTsData['en'], $dictEn);
        $this->langTsData['zh-cn'] = array_merge($this->langTsData['zh-cn'], $dictZhCn);
    }

    private function parseModelMethods($field, &$modelData): void
    {
        if (($field['designType'] ?? '') == 'array') {
            $modelData['fieldType'][$field['name']] = 'json';
        } elseif (!in_array($field['name'], ['create_time', 'update_time', 'updatetime', 'createtime'])
            && ($field['designType'] ?? '') == 'datetime'
            && in_array($field['type'] ?? '', ['int', 'bigint'])) {
            $modelData['fieldType'][$field['name']] = 'timestamp:Y-m-d H:i:s';
        }
        if (($field['designType'] ?? '') == 'spk') {
            $modelData['beforeInsertMixins']['snowflake'] = Helper::assembleStub('mixins/model/mixins/beforeInsertWithSnowflake', []);
        }
        $fieldName = parse_name($field['name'], 1);
        if (in_array($field['designType'] ?? '', $this->dtStringToArray)) {
            $modelData['methods'][] = Helper::assembleStub('mixins/model/getters/stringToArray', ['field' => $fieldName]);
            $modelData['methods'][] = Helper::assembleStub('mixins/model/setters/arrayToString', ['field' => $fieldName]);
        } elseif (($field['designType'] ?? '') == 'array') {
            $modelData['methods'][] = Helper::assembleStub('mixins/model/getters/jsonDecode', ['field' => $fieldName]);
        } elseif (($field['designType'] ?? '') == 'time') {
            $modelData['methods'][] = Helper::assembleStub('mixins/model/setters/time', ['field' => $fieldName]);
        } elseif (($field['designType'] ?? '') == 'editor') {
            $modelData['methods'][] = Helper::assembleStub('mixins/model/getters/htmlDecode', ['field' => $fieldName]);
        } elseif (($field['designType'] ?? '') == 'spk') {
            $modelData['methods'][] = Helper::assembleStub('mixins/model/getters/string', ['field' => $fieldName]);
        } elseif (in_array($field['type'] ?? '', ['float', 'decimal', 'double'])) {
            $modelData['methods'][] = Helper::assembleStub('mixins/model/getters/float', ['field' => $fieldName]);
        }
        if (($field['designType'] ?? '') == 'city') {
            $modelData['append'][] = $field['name'] . '_text';
            $modelData['methods'][] = Helper::assembleStub('mixins/model/getters/cityNames', [
                'field' => $fieldName . 'Text',
                'originalFieldName' => $field['name'],
            ]);
        }
    }

    private function parseSundryData($field, $table): void
    {
        if (($field['designType'] ?? '') == 'editor') {
            $this->formVueData['bigDialog'] = true;
            $this->controllerData['filterRule'] = "\n" . Helper::tab(2) . '$this->request->filter(\'clean_xss\');';
        }
        if (!empty($table['defaultSortField']) && !empty($table['defaultSortType'])) {
            $defaultSortField = "{$table['defaultSortField']},{$table['defaultSortType']}";
            if ($defaultSortField == 'id,desc') {
                $this->controllerData['attr']['defaultSortField'] = '';
            } else {
                $this->controllerData['attr']['defaultSortField'] = $defaultSortField;
                $this->indexVueData['defaultOrder'] = Helper::buildDefaultOrder($table['defaultSortField'], $table['defaultSortType']);
            }
        }
        if (($field['originalDesignType'] ?? '') == 'weigh' && $field['name'] != 'weigh') {
            $this->controllerData['attr']['weighField'] = $field['name'];
        }
    }

    private function getFormField($field, $columnDict, ?string $dbConnection = null): array
    {
        $formField = [
            ':label' => 't(\'' . $this->webTranslate . $field['name'] . '\')',
            'type' => $field['designType'],
            'v-model' => 'baTable.form.items!.' . $field['name'],
            'prop' => $field['name'],
        ];
        if ($columnDict || in_array($field['designType'], ['radio', 'checkbox', 'select', 'selects'])) {
            $formField[':input-attr']['content'] = $columnDict;
        } elseif ($field['designType'] == 'textarea') {
            $formField[':input-attr']['rows'] = (int)($field['form']['rows'] ?? 3);
            $formField['@keyup.enter.stop'] = '';
            $formField['@keyup.ctrl.enter'] = 'baTable.onSubmit(formRef)';
        } elseif (in_array($field['designType'], ['remoteSelect', 'remoteSelects'])) {
            $formField[':input-attr']['pk'] = $this->getRemoteSelectPk($field);
            $formField[':input-attr']['field'] = $field['form']['remote-field'] ?? 'name';
            $formField[':input-attr']['remoteUrl'] = $this->getRemoteSelectUrl($field);
        } elseif ($field['designType'] == 'number') {
            $formField[':input-attr']['step'] = (int)($field['form']['step'] ?? 1);
        } elseif ($field['designType'] == 'icon') {
            $formField[':input-attr']['placement'] = 'top';
        } elseif ($field['designType'] == 'editor') {
            $formField['@keyup.enter.stop'] = '';
            $formField['@keyup.ctrl.enter'] = 'baTable.onSubmit(formRef)';
        }
        if (!in_array($field['designType'], ['image', 'images', 'file', 'files', 'switch'])) {
            if (in_array($field['designType'], ['radio', 'checkbox', 'datetime', 'year', 'date', 'time', 'select', 'selects', 'remoteSelect', 'remoteSelects', 'city', 'icon'])) {
                $formField[':placeholder'] = "t('Please select field', { field: t('" . $this->webTranslate . $field['name'] . "') })";
            } else {
                $formField[':placeholder'] = "t('Please input field', { field: t('" . $this->webTranslate . $field['name'] . "') })";
            }
        }
        if (($field['defaultType'] ?? '') == 'INPUT') {
            $this->indexVueData['defaultItems'][$field['name']] = $field['default'];
        }
        if ($field['designType'] == 'editor') {
            $this->indexVueData['defaultItems'][$field['name']] = (($field['defaultType'] ?? '') == 'INPUT' && ($field['default'] ?? '')) ? $field['default'] : '';
        } elseif ($field['designType'] == 'array') {
            $this->indexVueData['defaultItems'][$field['name']] = "[]";
        } elseif (($field['defaultType'] ?? '') == 'INPUT' && in_array($field['designType'], $this->dtStringToArray) && str_contains($field['default'] ?? '', ',')) {
            $this->indexVueData['defaultItems'][$field['name']] = Helper::buildSimpleArray(explode(',', $field['default']));
        } elseif (($field['defaultType'] ?? '') == 'INPUT' && in_array($field['designType'], ['number', 'float'])) {
            $this->indexVueData['defaultItems'][$field['name']] = (float)($field['default'] ?? 0);
        }
        if (isset($field['default']) && in_array($field['designType'], ['switch', 'number', 'float', 'remoteSelect']) && $field['default'] == 0) {
            unset($this->indexVueData['defaultItems'][$field['name']]);
        }
        return $formField;
    }

    private function getRemoteSelectPk($field): string
    {
        $pk = $field['form']['remote-pk'] ?? 'id';
        $alias = '';
        if (!str_contains($pk, '.')) {
            if (($field['form']['remote-source-config-type'] ?? '') == 'crud' && !empty($field['form']['remote-model'])) {
                $alias = parse_name(basename(str_replace('\\', '/', $field['form']['remote-model']), '.php'));
            } else {
                $alias = $field['form']['remote-primary-table-alias'] ?? '';
            }
        }
        return !empty($alias) ? "$alias.$pk" : $pk;
    }

    private function getRemoteSelectUrl($field): string
    {
        if (($field['form']['remote-source-config-type'] ?? '') == 'crud' && !empty($field['form']['remote-controller'])) {
            $pathArr = [];
            $controller = explode(DIRECTORY_SEPARATOR, $field['form']['remote-controller']);
            $controller = str_replace('.php', '', $controller);
            $redundantDir = ['app' => 0, 'admin' => 1, 'controller' => 2];
            foreach ($controller as $key => $item) {
                if (!array_key_exists($item, $redundantDir) || $key !== $redundantDir[$item]) {
                    $pathArr[] = $item;
                }
            }
            $url = count($pathArr) > 1 ? implode('.', $pathArr) : ($pathArr[0] ?? '');
            return '/admin/' . $url . '/index';
        }
        return $field['form']['remote-url'] ?? '';
    }

    private function getTableColumn($field, $columnDict, string $fieldNamePrefix = '', string $translationPrefix = ''): array
    {
        $column = [
            'label' => "t('" . $this->webTranslate . $translationPrefix . $field['name'] . "')",
            'prop' => $fieldNamePrefix . $field['name'] . (($field['designType'] ?? '') == 'city' ? '_text' : ''),
            'align' => 'center',
        ];
        if (isset($field['table']['operator']) && $field['table']['operator'] == 'LIKE') {
            $column['operatorPlaceholder'] = "t('Fuzzy query')";
        }
        if (!empty($field['table'])) {
            $column = array_merge($column, $field['table']);
            $column['comSearchInputAttr'] = str_attr_to_array($column['comSearchInputAttr'] ?? '');
        }
        $columnReplaceValue = ['tag', 'tags', 'switch'];
        if (!in_array($field['designType'] ?? '', ['remoteSelect', 'remoteSelects'])
            && ($columnDict || (isset($field['table']['render']) && in_array($field['table']['render'], $columnReplaceValue)))) {
            $column['replaceValue'] = $columnDict;
        }
        if (isset($column['render']) && $column['render'] == 'none') {
            unset($column['render']);
        }
        return $column;
    }

    private function getColumnDict($column, string $translationPrefix = ''): array
    {
        $dict = [];
        if (in_array($column['type'] ?? '', ['enum', 'set'])) {
            $dataType = str_replace(' ', '', $column['dataType'] ?? '');
            $columnData = substr($dataType, stripos($dataType, '(') + 1, -1);
            $columnData = explode(',', str_replace(["'", '"'], '', $columnData));
            foreach ($columnData as $columnDatum) {
                $dict[$columnDatum] = $column['name'] . ' ' . $columnDatum;
            }
        }
        $dictData = [];
        Helper::getDictData($dictData, $column, 'zh-cn', $translationPrefix);
        if ($dictData) {
            unset($dictData[$translationPrefix . $column['name']]);
            foreach ($dictData as $key => $item) {
                $keyName = str_replace($translationPrefix . $column['name'] . ' ', '', $key);
                $dict[$keyName] = "t('" . $this->webTranslate . $key . "')";
            }
        }
        return $dict;
    }
}
