"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.genCommonSqlMethod = exports.genDefaultProps = exports.genPropTypes = exports.genClassMethods = exports.genStaticProps = exports.genFormInitialValues = exports.genConstructor = exports.genRenderMethod = exports.genImports = exports.handleGeneralMethods = exports.handleCycleMethods = void 0;
const t = require("@babel/types");
const utils_1 = require("../utils/utils");
const LONG = 'Long';
const FLOAT = 'Float';
const INTEGER = 'Integer';
const TEXT = 'Text';
const BOOLEAN = 'Boolean';
const DATE = 'Date';
const DATETIME = 'DateTime';
const COMMONSQL = 'commonSql';
const FDX_COMPONENTS = ['PopEdit', 'RichEditor', 'Modal', 'Drawer'];
function getIdentifier(member, key) {
    return member.datas[key] ? t.identifier('state') : t.identifier('props');
}
const nestedMethodsVisitor = {
    VariableDeclaration(path) {
        const { declarations } = path.node;
        declarations.forEach((d) => {
            if (t.isMemberExpression(d.init)) {
                const key = d.init.property.name;
                d.init.object = t.memberExpression(t.thisExpression(), getIdentifier(this.member, key));
            }
        });
        this.blocks.push(path.node);
    },
    ExpressionStatement(path) {
        const { expression } = path.node;
        if (t.isAssignmentExpression(expression)) {
            const { right } = expression;
            const letfNode = expression.left.property;
            path.node.expression = t.callExpression(t.memberExpression(t.thisExpression(), t.identifier('setState')), [
                t.objectExpression([t.objectProperty(letfNode, right)]),
            ]);
        }
        if (t.isCallExpression(expression) && !t.isThisExpression(expression.callee.object)) {
            path.traverse({
                ThisExpression(memPath) {
                    const key = memPath.parent.property.name;
                    memPath.replaceWith(t.memberExpression(t.thisExpression(), getIdentifier(this.member, key)));
                    memPath.stop();
                },
            }, { member: this.member });
        }
        this.blocks.push(path.node);
    },
    ReturnStatement(path) {
        path.traverse({
            ThisExpression(memPath) {
                const key = memPath.parent.property.name;
                memPath.replaceWith(t.memberExpression(t.thisExpression(), getIdentifier(this.member, key)));
                memPath.stop();
            },
        }, { member: this.member });
        this.blocks.push(path.node);
    },
};
function createClassMethod(path, member, name) {
    const blocks = [];
    let { params } = path.node;
    if (name === 'componentDidCatch') {
        params = [t.identifier('error'), t.identifier('info')];
    }
    path.traverse(nestedMethodsVisitor, { blocks, member });
    if (name === 'init') {
        return blocks;
    }
    return t.classMethod('method', t.identifier(name), params, t.blockStatement(blocks));
}
const handleCycleMethods = (path, collect, member, cycleName) => {
    collect.classMethods[cycleName] = createClassMethod(path, member, cycleName);
};
exports.handleCycleMethods = handleCycleMethods;
const handleGeneralMethods = (path, collect, member, name) => {
    collect.classMethods[name] = createClassMethod(path, member, name);
};
exports.handleGeneralMethods = handleGeneralMethods;
const genImports = (path, collect, member, hasDate, hasUpload, manual, pageName, pageAction, fishxIcons, hasTableEdit, expandableBlocks) => {
    const nodeLists = path.node.body;
    // import React
    const importReact = t.importDeclaration([t.importDefaultSpecifier(t.identifier('React')), t.importSpecifier(t.identifier('Component'), t.identifier('Component'))], t.stringLiteral('react'));
    // 引入action模块
    if (Array.isArray(pageAction)) {
        pageAction.forEach((action) => {
            collect.imports.push(t.importDeclaration([
                t.importDefaultSpecifier(t.identifier(action.name)),
            ], t.stringLiteral(`./lc-actions/${action.name}`)));
        });
    }
    // import classNames lib
    collect.imports.push(t.importDeclaration([t.importDefaultSpecifier(t.identifier('classNames'))], t.stringLiteral('classnames')));
    // import page css styles
    collect.imports.push(t.importDeclaration([t.importDefaultSpecifier(t.identifier('styles'))], t.stringLiteral('./index.css')));
    if (Object.keys(member.props).length) {
        const importPropTypes = t.importDeclaration([t.importDefaultSpecifier(t.identifier('PropTypes'))], t.stringLiteral('prop-types'));
        collect.imports.push(importPropTypes);
    }
    // 获取所有的区块信息
    let allBlocks = member.pageBlocks.concat(expandableBlocks);
    allBlocks = Array.from(new Set(allBlocks));
    allBlocks.forEach((v) => {
        let impPath = manual ? `@lowcode/blocks/${v}` : `@/components/${v}`;
        // treeV2从自定义组件包里获取
        if (v === 'TreeV2' || v === 'TreeSelectV2') {
            impPath = '@/components/LowcodeTree';
            collect.imports.push(t.importDeclaration([t.importSpecifier(t.identifier(v), t.identifier(v))], t.stringLiteral(impPath)));
        }
        else {
            collect.imports.push(t.importDeclaration([t.importDefaultSpecifier(t.identifier(v))], t.stringLiteral(impPath)));
        }
    });
    member.pageWidgets.forEach(v => {
        collect.imports.push(t.importDeclaration([t.importDefaultSpecifier(t.identifier(v))], t.stringLiteral(`@/widgets/${v}`)));
    });
    if (member.component.length) {
        const importComponent = [];
        const fdxImportComponents = [];
        member.component.forEach((v) => {
            if (v === 'Form') {
                // collect.imports.push(t.importDeclaration([t.importSpecifier(t.identifier('Form'), t.identifier('SimpleForm'))], t.stringLiteral('@whalecloud/fdx'))); // import SimpleForm
                fdxImportComponents.push(t.importSpecifier(t.identifier('Form'), t.identifier('SimpleForm')));
            }
            else if (FDX_COMPONENTS.includes(v)) {
                fdxImportComponents.push(t.importSpecifier(t.identifier(v), t.identifier(v)));
            }
            else if (v === 'FdxList') {
                importComponent.push(t.importSpecifier(t.identifier('FdxList'), t.identifier('List')));
            }
            else {
                importComponent.push(t.importSpecifier(t.identifier(v), t.identifier(v)));
            }
        });
        if (hasUpload && member.component.indexOf('Icon') === -1) {
            importComponent.push(t.importSpecifier(t.identifier('Icon'), t.identifier('Icon')));
        }
        collect.imports.push(t.importDeclaration(importComponent, t.stringLiteral('antd')));
        collect.imports.push(t.importDeclaration(fdxImportComponents, t.stringLiteral('@whalecloud/fdx'))); // import component from @whalecloud/fdx
    }
    if (member.extraComponent.length) {
        const importComponent = [];
        member.extraComponent.forEach((v) => {
            importComponent.push(t.importSpecifier(t.identifier(v), t.identifier(v)));
        });
        collect.imports.push(t.importDeclaration(importComponent, t.stringLiteral('@fishx/fishx-plus')));
    }
    if (member.thirdPartyComponent.length) {
        member.thirdPartyComponent.forEach((v) => {
            if (v === 'InfiniteScroll') {
                collect.imports.push(t.importDeclaration([t.importDefaultSpecifier(t.identifier(v))], t.stringLiteral('react-infinite-scroll-component')));
            }
        });
    }
    if (member.mobileComponent.length) {
        const importComponent = [];
        member.mobileComponent.forEach((v) => {
            if (v === 'List.Item') {
                importComponent.push(t.importSpecifier(t.identifier('List'), t.identifier('List')));
            }
            else {
                importComponent.push(t.importSpecifier(t.identifier(v), t.identifier(v)));
            }
        });
        collect.imports.push(t.importDeclaration(importComponent, t.stringLiteral('@whalecloud/fishx-mobile')));
    }
    if (hasDate) {
        collect.imports.push(t.importDeclaration([t.importDefaultSpecifier(t.identifier('moment'))], t.stringLiteral('moment')));
    }
    if (hasTableEdit) {
        collect.imports.push(t.importDeclaration([t.importDefaultSpecifier(t.identifier('TableEdit'))], t.stringLiteral('@fishx/table-edit')));
    }
    if (hasUpload) {
        collect.imports.push(t.importDeclaration([t.importSpecifier(t.identifier('PlusOutlined'), t.identifier('PlusOutlined'))], t.stringLiteral('@fishx/icons')));
    }
    if (member.fishx.length) {
        const importFishx = [];
        member.fishx.forEach((v) => {
            importFishx.push(t.importSpecifier(t.identifier(v), t.identifier(v)));
        });
        collect.imports.push(t.importDeclaration(importFishx, t.stringLiteral('fishx')));
    }
    collect.imports.push(t.importDeclaration([t.importSpecifier(t.identifier('RemoteComponent'), t.identifier('RemoteComponent'))], t.stringLiteral('@fishx/remote-component')));
    collect.imports.push(t.importDeclaration([t.importSpecifier(t.identifier('List'), t.identifier('List'))], t.stringLiteral('@/utils/ProjectType')));
    collect.imports.push(t.importDeclaration([t.importSpecifier(t.identifier('QueryMap'), t.identifier('QueryMap'))], t.stringLiteral(`@/types/${pageName}`)));
    // import fishx-icons
    if (fishxIcons.length > 0) {
        // 去重
        const allImportIcons = Array.from(new Set(fishxIcons));
        allImportIcons.forEach(item => {
            collect.imports.push(t.importDeclaration([t.importSpecifier(t.identifier(item), t.identifier(item))], t.stringLiteral('@fishx/icons')));
        });
    }
    collect.imports.push(importReact);
    collect.imports.forEach((node) => nodeLists.unshift(node));
};
exports.genImports = genImports;
const genRenderMethod = (path) => {
    // computed props
    const blocks = [t.returnStatement(t.identifier('$DOM$'))];
    const render = t.classMethod('method', t.identifier('render'), [], t.blockStatement(blocks));
    path.node.body.push(render);
};
exports.genRenderMethod = genRenderMethod;
const genConstructor = (path, pageVar, hasInit, formInitialValues) => {
    const nodeLists = path.node.body;
    const blocks = [t.expressionStatement(t.callExpression(t.super(), [t.identifier('props')]))];
    if (pageVar.length) {
        const varStatement = [];
        pageVar.forEach((v) => {
            if (v.defaultValue) {
                let valueExp;
                switch (v.type) {
                    case LONG:
                    case FLOAT:
                    case INTEGER:
                        valueExp = t.numericLiteral(Number(v.defaultValue));
                        break;
                    case TEXT:
                        valueExp = v.defaultValue === "''" ? t.stringLiteral('') : t.stringLiteral(v.defaultValue);
                        break;
                    case BOOLEAN:
                        valueExp = t.booleanLiteral(v.defaultValue !== 'false');
                        break;
                    case DATE:
                    case DATETIME:
                        valueExp = t.stringLiteral(v.defaultValue);
                        break;
                    case COMMONSQL:
                        valueExp = t.objectExpression([t.objectProperty(t.identifier('list'), t.arrayExpression())]);
                        break;
                    default:
                        valueExp = t.identifier(v.defaultValue);
                        break;
                }
                if (v.defaultValue && v.defaultValue.indexOf('#{') !== -1) {
                    const outProps = v.defaultValue.replace(/(?:#{)|(?:})/g, '');
                    valueExp = (0, utils_1.objValueStr2AST)(`props.${outProps}`);
                }
                varStatement.push(t.objectProperty(t.identifier(v.name), valueExp));
                // 收集 Form 组件内部子组件双向绑定变量，生成 Form 组件初始值 用于 resetFields
                if (Object.keys(formInitialValues).length > 0) {
                    Object.values(formInitialValues).forEach(stateVals => {
                        if (stateVals && stateVals[v.name]) {
                            stateVals[v.name].value = valueExp;
                        }
                    });
                }
            }
        });
        blocks.push(t.expressionStatement(t.assignmentExpression('=', t.memberExpression(t.thisExpression(), t.identifier('state')), t.objectExpression(varStatement))));
    }
    if (hasInit) {
        blocks.push(t.expressionStatement(t.callExpression(t.memberExpression(t.thisExpression(), t.identifier('initialize')), [])));
    }
    const ctro = t.classMethod('constructor', t.identifier('constructor'), [t.identifier('props')], t.blockStatement(blocks));
    nodeLists.push(ctro);
};
exports.genConstructor = genConstructor;
// 生成 Form 组件初始值 用于 resetFields
const genFormInitialValues = (path, formInitialValues) => {
    const nodeLists = path.node.body;
    if (Object.keys(formInitialValues).length > 0) {
        Object.keys(formInitialValues).forEach(form => {
            const varStatement = [];
            if (Object.keys(formInitialValues[form]).length > 0) {
                Object.keys(formInitialValues[form]).forEach(formVals => {
                    if (formInitialValues[form][formVals]) {
                        varStatement.push(t.objectProperty(t.identifier(formVals), t.objectExpression([
                            t.objectProperty(t.identifier('name'), t.stringLiteral(formInitialValues[form][formVals].name)),
                            t.objectProperty(t.identifier('value'), formInitialValues[form][formVals].value),
                        ])));
                    }
                });
            }
            if (varStatement.length > 0) {
                const formInitVals = t.expressionStatement(t.assignmentExpression('=', t.identifier(`${form}InitialValues`), t.objectExpression(varStatement)));
                nodeLists.push(formInitVals);
            }
        });
    }
};
exports.genFormInitialValues = genFormInitialValues;
const genStaticProps = (path, member) => {
    const { props } = member;
    const nodeLists = path.node.body;
    if (Object.keys(props).length) {
        nodeLists.push((0, exports.genPropTypes)(props));
        nodeLists.push((0, exports.genDefaultProps)(props));
    }
};
exports.genStaticProps = genStaticProps;
const genClassMethods = (path, collect) => {
    const nodeLists = path.node.body;
    const methods = collect.classMethods;
    Object.keys(methods).forEach((key) => {
        if (key !== 'created') {
            if (key === 'mounted') {
                nodeLists.push(t.classMethod('method', t.identifier('componentDidMount'), [], t.blockStatement(methods[key])));
            }
            else if (key === 'destroyed') {
                nodeLists.push(t.classMethod('method', t.identifier('componentWillUnmount'), [], t.blockStatement(methods[key])));
            }
            else {
                nodeLists.push(t.classProperty(t.identifier(key), t.arrowFunctionExpression([t.identifier('event'), t.identifier('ctx')], t.blockStatement(methods[key]))));
            }
        }
    });
};
exports.genClassMethods = genClassMethods;
const genPropTypes = (props) => {
    const properties = [];
    const keys = Object.keys(props);
    for (let i = 0, l = keys.length; i < l; i += 1) {
        const key = keys[i];
        const obj = props[key];
        const identifier = t.identifier(key);
        let val = t.memberExpression(t.identifier('PropTypes'), t.identifier('any'));
        if (Array.isArray(obj.type) || obj.type === 'array') {
            if (Array.isArray(obj.type)) {
                const elements = [];
                obj.type.forEach((val) => {
                    elements.push(t.memberExpression(t.identifier('PropTypes'), t.identifier(val)));
                });
                val = t.callExpression(t.memberExpression(t.identifier('PropTypes'), t.identifier('oneOfType')), [t.arrayExpression(elements)]);
            }
            else {
                val = obj.required
                    ? t.memberExpression(t.memberExpression(t.identifier('PropTypes'), t.identifier('array')), t.identifier('isRequired'))
                    : t.memberExpression(t.identifier('PropTypes'), t.identifier('array'));
            }
        }
        else {
            val = obj.required
                ? t.memberExpression(t.memberExpression(t.identifier('PropTypes'), t.identifier(obj.type)), t.identifier('isRequired'))
                : t.memberExpression(t.identifier('PropTypes'), t.identifier(obj.type));
        }
        properties.push(t.objectProperty(identifier, val));
    }
    // Babel does't support to create static class property???
    return t.classProperty(t.identifier('static propTypes'), t.objectExpression(properties), null, []);
};
exports.genPropTypes = genPropTypes;
const genDefaultProps = (props) => {
    const properties = [];
    const keys = Object.keys(props);
    for (let i = 0, l = keys.length; i < l; i += 1) {
        const key = keys[i];
        const obj = props[key];
        const identifier = t.identifier(key);
        let val = t.stringLiteral('error');
        if (Array.isArray(obj.type)) {
            const type = typeof obj.defaultValue;
            if (type !== 'undefined') {
                const v = obj.defaultValue;
                if (type === 'number') {
                    val = t.numericLiteral(Number(v));
                }
                else if (type === 'string') {
                    val = t.stringLiteral(v);
                }
                else {
                    val = t.booleanLiteral(v);
                }
            }
            else {
                // eslint-disable-next-line no-continue
                continue;
            }
        }
        else if (obj.type === 'array') {
            val = t.arrayExpression(obj.defaultValue.elements);
        }
        else if (obj.type === 'object') {
            val = t.objectExpression(obj.defaultValue.properties);
        }
        else {
            switch (obj.type) {
                case 'string':
                    val = t.stringLiteral(obj.defaultValue);
                    break;
                case 'boolean':
                    val = t.booleanLiteral(obj.defaultValue);
                    break;
                case 'number':
                    val = t.numericLiteral(Number(obj.defaultValue));
                    break;
                default:
                    break;
            }
        }
        properties.push(t.objectProperty(identifier, val));
    }
    // Babel does't support to create static class property???
    return t.classProperty(t.identifier('static defaultProps'), t.objectExpression(properties), null, []);
};
exports.genDefaultProps = genDefaultProps;
const genCommonSqlMethod = (blocks, initCommonSqlQuery, remoteOptions, picklists) => {
    if (picklists.length) {
        const paramExp = [];
        const assignExp = [];
        picklists.forEach((ele) => {
            paramExp.push(t.objectExpression([
                t.objectProperty(t.identifier('id'), t.stringLiteral(ele.id)),
                t.objectProperty(t.identifier('name'), t.stringLiteral(ele.name)),
            ]));
            assignExp.push(t.objectProperty(t.identifier(ele.name), (0, utils_1.objValueStr2AST)(`GetPickListRes.${ele.name}.picklistValues`)));
        });
        blocks.push(t.variableDeclaration('let', [
            t.variableDeclarator(t.identifier('GetPickListRes'), t.awaitExpression(t.callExpression(t.identifier('call'), [t.stringLiteral('GetPickList'), t.arrayExpression(paramExp)]))),
        ]));
        blocks.push(t.expressionStatement(t.awaitExpression(t.callExpression(t.identifier('setStatePromise'), [t.thisExpression(), t.objectExpression(assignExp)]))));
    }
    remoteOptions.forEach((v) => {
        const entityName = v.value;
        const fetchExp = t.awaitExpression(t.callExpression(t.identifier('call'), [t.stringLiteral(`Get${entityName}ByFilter`)]));
        const res = t.identifier(`Get${entityName}ByFilter_res`);
        blocks.push(t.variableDeclaration('const', [t.variableDeclarator(res, fetchExp)]));
        blocks.push(t.expressionStatement(t.awaitExpression(t.callExpression(t.identifier('setStatePromise'), [
            t.thisExpression(),
            t.objectExpression([t.objectProperty(t.identifier(v.name), t.callExpression(t.identifier('transRemoteOptions'), [res]))]),
        ]))));
    });
    initCommonSqlQuery.forEach((v) => {
        const variablesExp = [];
        const variables = v.variables || [];
        variables.forEach((v) => {
            const vartype = v.varType;
            const varArr = v.expression
                .replace(/["|'](.*?)["|']/g, '')
                .replace(/true/g, '')
                .replace(/false/g, '')
                .match(/[a-zA-Z]([a-zA-Z]|[0-9]|_|\.)*/g) || [];
            const varName = varArr[0];
            if (varName) {
                let replacedStr = '';
                if (vartype === 'action') {
                    replacedStr = varName;
                }
                else if (vartype === 'page') {
                    replacedStr = `this.state.${varName}`;
                }
                else {
                    replacedStr = `this.props.match.params.${varName}`;
                }
                variablesExp.push(t.objectProperty(t.identifier(varName), t.identifier((0, utils_1.newReplaceAll)(v.expression, varName, replacedStr))));
            }
        });
        if (typeof v.pageSize === 'string' && typeof v.pageIndex === 'string') {
            let pageSize;
            let pageIndex;
            v.pageSize.replace(/#{([\s\S]*?)}/g, (match, key) => {
                pageSize = key;
            });
            v.pageIndex.replace(/#{([\s\S]*?)}/g, (match, key) => {
                pageIndex = key;
            });
            if (pageSize) {
                variablesExp.push(t.objectProperty(t.identifier('pageSize'), (0, utils_1.objValueStr2AST)(`this.state.${pageSize}`)));
            }
            if (pageIndex) {
                variablesExp.push(t.objectProperty(t.identifier('pageIndex'), (0, utils_1.objValueStr2AST)(`this.state.${pageIndex}`)));
            }
        }
        const _res = t.identifier(`${v.name}_res`);
        blocks.push(t.variableDeclaration('let', [
            t.variableDeclarator(t.identifier(`${v.name}_res`), t.awaitExpression(t.callExpression(t.identifier('get'), [t.stringLiteral(v.name), t.objectExpression(variablesExp), t.identifier('QueryMap')]))),
        ]));
        blocks.push(t.expressionStatement(t.awaitExpression(t.callExpression(t.identifier('setStatePromise'), [t.thisExpression(), t.objectExpression([t.objectProperty(t.identifier(v.name), _res)])]))));
        if (v.afterFetch) {
            blocks.push(t.expressionStatement(t.callExpression((0, utils_1.objValueStr2AST)(`this.${v.afterFetch}`), [])));
        }
    });
};
exports.genCommonSqlMethod = genCommonSqlMethod;
