"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getWxmlTag = exports.filterMaterial = exports.installMaterials = void 0;
const path = __importStar(require("path"));
const util_1 = require("util");
const fs = __importStar(require("fs-extra"));
const weapps_core_1 = require("@cloudbase/lowcode-generator/lib/weapps-core");
const config_1 = require("../config");
const mp_1 = require("@cloudbase/lowcode-generator/lib/generator/config/mp");
const util_2 = require("../util");
const util_3 = require("./util");
const wxml_1 = require("./wxml");
const generateFiles_1 = __importStar(require("../util/generateFiles"));
const lowcode_1 = require("./lowcode");
const net_1 = require("../util/net");
const name_mangler_1 = __importDefault(require("@cloudbase/lowcode-generator/lib/generator/util/name-mangler"));
const junk = __importStar(require("../util/junk"));
const cals_1 = require("@cloudbase/cals");
const templateDir = `${config_1.appTemplateDir}/mp/`;
async function installMaterials(ctx, outDir, usedMeta, weapps) {
    let { materialLibs: _materialLibs, isBrowserMpBuilder } = ctx;
    const weappsList = ctx.isMixMode ? weapps : weapps.filter((item) => !item.rootPath);
    let materialLibs = _materialLibs.filter((lib) => usedMeta.component[lib.name] || usedMeta.action[lib.name]);
    // #1 Download uploaded libs
    const localPkg = (0, util_2.getCurrentPackageJson)();
    await Promise.all(materialLibs
        .filter((lib) => !lib.isComposite)
        .map(async (lib) => {
        const { name, version, mpPkgUrl } = lib;
        let materialsSrcDir = '';
        const materialId = `${name}@${version}`;
        // #1 Download material
        if (localPkg && localPkg.name === name) {
            // If the target materials is current developing one skip download
            materialsSrcDir = path.join(process.cwd(), 'build', 'mp');
        }
        else {
            materialsSrcDir = path.join(config_1.sharedMaterialsDir, `${name}-mp@${version}`);
            const noCache = mpPkgUrl.indexOf('127.0.0.1') >= 0;
            await downloadMaterial(mpPkgUrl, materialsSrcDir, ctx.isBrowserMpBuilder, noCache);
        }
        function libUpdated(libDir, version) {
            const meta = (0, util_2.readComponentLibMata)(libDir);
            if (!meta) {
                return true;
            }
            if (meta.version !== lib.version) {
                return true;
            }
        }
        const usingMaterialMap = {};
        // 混合模式下，各个子包获取自己使用过的组件和复合组件（会出现冗余）
        // 统一都放在根目录下，可以减少冗余
        await Promise.all(weappsList.map(async (app) => {
            const targetDir = path.join(outDir, config_1.materialsDirName, name);
            if (usingMaterialMap[targetDir]) {
                return;
            }
            else {
                usingMaterialMap[targetDir] = true;
            }
            if (libUpdated(targetDir, version)) {
                const materialsSrcDirPath = path.join(materialsSrcDir, 'src');
                if (fs.existsSync(materialsSrcDirPath)) {
                    console.log(`Copying material ${materialId} from ${isBrowserMpBuilder ? materialsSrcDirPath : materialsSrcDir}/src to ${targetDir}`);
                    // #2 从根目录 copy meta 文件
                    const metaJosnPath = path.join(materialsSrcDir, 'meta.json');
                    if (fs.existsSync(metaJosnPath)) {
                        !isBrowserMpBuilder
                            ? await fs.copy(metaJosnPath, path.join(targetDir, 'meta.json'))
                            : (0, generateFiles_1.copyRecursiveSync)(metaJosnPath, path.join(targetDir, 'meta.json'));
                    }
                    // #3 copy 组件库代码文件到项目目录
                    !isBrowserMpBuilder
                        ? await fs.copy(materialsSrcDirPath, targetDir, {
                            filter(src, dest) {
                                const path = src.split('/');
                                return !junk.is(path[path.length - 1]);
                            },
                        })
                        : (0, generateFiles_1.copyRecursiveSync)(materialsSrcDirPath, targetDir, {
                            filter: filterMaterial,
                        });
                }
                else {
                    console.log(`Copying material ${materialId} from ${materialsSrcDir} to ${targetDir}`);
                    // #2 link material to current project
                    !isBrowserMpBuilder
                        ? await fs.copy(materialsSrcDir, targetDir, {
                            filter(src, dest) {
                                const path = src.split('/');
                                return !junk.is(path[path.length - 1]);
                            },
                        })
                        : (0, generateFiles_1.copyRecursiveSync)(materialsSrcDir, targetDir, {
                            filter: filterMaterial,
                        });
                }
            }
            const libMeta = (0, util_2.readComponentLibMata)(targetDir);
            if (!lib.components) {
                lib.components = Object.keys((libMeta === null || libMeta === void 0 ? void 0 : libMeta.components) || {}).map((name) => {
                    var _a;
                    return ({
                        name,
                        meta: (_a = libMeta === null || libMeta === void 0 ? void 0 : libMeta.components[name]) === null || _a === void 0 ? void 0 : _a.meta,
                    });
                });
            }
            lib.styles = libMeta === null || libMeta === void 0 ? void 0 : libMeta.styles;
            lib.dependencies = libMeta === null || libMeta === void 0 ? void 0 : libMeta.dependencies;
        }));
    }));
    // clean unused comps
    ctx.materialLibs = materialLibs;
    materialLibs.forEach((lib) => {
        lib.components = lib.components.filter((comp) => { var _a, _b; return (_b = (_a = usedMeta.component[lib.name]) === null || _a === void 0 ? void 0 : _a.has) === null || _b === void 0 ? void 0 : _b.call(_a, comp.name); });
    });
    // populate cmp.materialName
    materialLibs.map((lib) => {
        lib.components.map((comp) => {
            comp.materialName = lib.name;
        });
    });
    materialLibs.map((lib) => {
        lib.dependencies = lib.dependencies || {};
        lib.components.map((cmp) => {
            cmp.meta.syncProps = {};
            const { dataForm = {} } = cmp;
            for (const prop in dataForm) {
                const { inputProp, syncProp } = dataForm[prop];
                if (syncProp || inputProp) {
                    cmp.meta.syncProps[prop] = syncProp || inputProp;
                }
            }
            if (lib.isComposite) {
                cmp.meta.platforms = {
                    mp: {
                        path: `${cmp.name}/index`,
                    },
                };
                lib.dependencies = { ...lib.dependencies, ...cmp.npmDependencies };
            }
        });
    });
    // Collection infomation from components to lib meta
    const compositedLibs = materialLibs.filter((lib) => lib.isComposite);
    // #2 Generate composited libs
    await Promise.all(compositedLibs.map(async (lib) => {
        console.log(`Generate composited library ${lib.name}`);
        await (0, util_2.writeLibCommonRes2file)(lib, path.join(outDir, config_1.materialsDirName, lib.name, 'libCommonRes'));
        await Promise.all(lib.components.map(async (cmp) => {
            return generateCompositeComponent({
                ...ctx,
                /**
                 * 此处强行覆盖为 rpx 是为了兼容老的复合组件
                 * $template 应该跟随应用的配置
                 */
                processCssUnit: lib.name !== '$template' ? 'rpx' : ctx.processCssUnit,
                // 只生成在主目录中，减少冗余
                // rootPath: app.rootPath || '', // 主包是没有 rootPath 的
            }, cmp, path.join(outDir, config_1.materialsDirName), lib.compLibCommonResource);
        }));
    }));
}
exports.installMaterials = installMaterials;
/**
 * 过滤组件库文件
 * @param src 源文件
 * @param dest 目标文件
 * @returns boolean
 */
function filterMaterial(src, dest) {
    const srcPath = src.split('/');
    return !junk.is(srcPath[srcPath.length - 1]);
}
exports.filterMaterial = filterMaterial;
async function downloadMaterial(zipUrl, dstFolder, isBrowser = false, noCache = false) {
    if (!noCache && fs.existsSync(path.join(dstFolder, 'meta.json')))
        return;
    await (0, net_1.downloadZip)(zipUrl, dstFolder, isBrowser, noCache);
}
async function generateCompositeComponent(ctx, compositedComp, outDir, compLibCommonResource) {
    const compositeCtx = {
        ...ctx,
        isPage: false,
        enableLoading: false,
    };
    const { materialName } = compositedComp;
    const componentDir = path.join(outDir, materialName, compositedComp.name);
    const LOWCODE_DIR_NAME = 'lowcode';
    console.log(`Generating composited component ${materialName}:${compositedComp.name} to ${componentDir}`);
    const wxmlDataPrefix = (0, mp_1.getWxmlDataPrefix)(!compositeCtx.isProduction);
    // # Generating page
    const usingComponents = {};
    const componentGenerics = {};
    const componentInstances = (0, util_3.processRepeaterSchema)(compositeCtx, compositedComp.componentInstances);
    const cmpContainer = Object.values(componentInstances)[0];
    const wxml = (0, wxml_1.generateWxml)(compositeCtx, componentInstances, `Component ${materialName}:${compositedComp.name}`, wxmlDataPrefix, usingComponents, componentGenerics, (cmp, node) => {
        if (cmp === cmpContainer) {
            // Set className & style passed from parent for root component
            const { attributes } = node;
            const classAttrName = (0, mp_1.getClassAttrName)(node.name);
            const oldClass = attributes[classAttrName];
            attributes[classAttrName] = `${(0, weapps_core_1.getCompositedComponentClass)(compositedComp)} ${oldClass} {{className}}`;
            attributes.style += ';{{style}}';
        }
    });
    // prepare form field change events
    const { syncProps } = compositedComp.meta;
    const formEvents = {};
    Object.keys(syncProps).map((prop) => {
        const config = syncProps[prop];
        const configs = Array.isArray(config) ? config : [config];
        configs.forEach(({ changeEvent, valueFromEvent, isFormField }) => {
            if (isFormField) {
                formEvents[changeEvent] = valueFromEvent;
            }
        });
    });
    const propDefs = { ...compositedComp.dataForm };
    Object.keys(propDefs).map((p) => {
        if (propDefs[p]['x-component'] === mp_1.WeappsCompSelect) {
            delete propDefs[p];
        }
    });
    const codes = (0, cals_1.processRuntimeCodeResources)({ id: '$comp' }, compositedComp.lowCodes, 'component');
    const importor = (0, util_2.generateLowcodeImportor)(codes);
    const pageFileData = {
        'index.js': {
            materialName,
            propDefs,
            handlers: compositedComp.lowCodes
                .filter((m) => m.type === cals_1.ECodeType.HANDLER_FN && m.name !== cals_1.ECodeName.PLACEHOLDER)
                .map((m) => m.name),
            eventHandlers: (0, util_3.createEventHandlers)(compositeCtx, componentInstances, weapps_core_1.COMPONENT_API_PREFIX),
            // protectEventKeys: builtinMpEvents,
            emitEvents: (compositedComp.emitEvents || []).map((evt) => evt.eventName),
            widgetProps: (0, util_3.createWidgetProps)(compositeCtx, componentInstances),
            compApi: weapps_core_1.COMPONENT_API_PREFIX,
            jsonSchemaType2jsClass: mp_1.jsonSchemaType2jsClass,
            key: `${compositedComp.materialName}:${compositedComp.name}`,
            dataBinds: (0, util_3.createDataBinds)(compositeCtx, componentInstances),
            debug: !compositeCtx.isProduction,
            /**
             * @deprecated
             */
            stringifyObj: util_1.inspect,
            // dataPropNames: wxmlDataPrefix,
            formEvents: Object.keys(formEvents).length > 0 ? formEvents : null,
            config: compositedComp.compConfig,
            importor,
        },
        'index.json': { usingComponents, componentGenerics },
        'index.wxml': {
            content: wxml,
        },
        'index.wxss': {
            importStyles: importor.styles.map((mod) => path.posix.join(LOWCODE_DIR_NAME, (0, weapps_core_1.getCodeModuleFilePath)('global', mod, { style: '.wxss' }))),
            content: (0, util_3.generateScopedStyleText)(componentInstances),
        },
    };
    // Generating file by template and data
    await (0, generateFiles_1.default)(pageFileData, `${templateDir}/component`, componentDir);
    // #3 writing lowcode files
    /**
     * 低码没有开放 index 类别，直接去掉
     */
    // if (!codes.find((m) => m.name === 'index')) {
    //   // @ts-ignore
    //   codes.push({
    //     code: 'export default {}',
    //     name: 'index',
    //     path: 'index',
    //   });
    // }
    codes.map((mod) => {
        let themeCode;
        if (mod.type === cals_1.ECodeType.STYLE && compLibCommonResource) {
            themeCode = `
         ${compLibCommonResource.theme.variable || ''}
         ${compLibCommonResource.class || ''}
         ${compLibCommonResource.theme.class || ''}
      `;
        }
        /**
         * 低码没有开放 index 类别，直接去掉
         */
        if (mod.name === 'index') {
            return;
        }
        return (0, lowcode_1.writeCode2file)(compositeCtx, mod, path.join(componentDir, LOWCODE_DIR_NAME), { comp: compositedComp }, themeCode);
    });
    // await writeLowCodeFiles(weapp, appRoot)
    // await generateFramework(weapp, appRoot)
}
/**
 * {
 * gsd: {
 * input: 'input'
 * }
 * }
 */
const NAME_MANAGER = new name_mangler_1.default({ blackList: mp_1.builtinMpTags });
function getWxmlTag(ctx, cmp, nameMangler) {
    var _a, _b, _c, _d, _e, _f;
    const { moduleName, name } = cmp;
    const materialLib = ctx.materialLibs.find((lib) => lib.name === moduleName);
    const miniprogramPlugin = (_a = ctx.miniprogramPlugins) === null || _a === void 0 ? void 0 : _a.find((plugin) => plugin.name === moduleName);
    let tagName = name.toLocaleUpperCase();
    let compPath;
    const components = (materialLib === null || materialLib === void 0 ? void 0 : materialLib.components) || (miniprogramPlugin === null || miniprogramPlugin === void 0 ? void 0 : miniprogramPlugin.componentConfigs);
    const findComponent = components === null || components === void 0 ? void 0 : components.find((comp) => comp.name === name);
    if (!findComponent) {
        return { tagName };
    }
    if (materialLib) {
        let cmpMeta = (findComponent === null || findComponent === void 0 ? void 0 : findComponent.meta) || { platforms: undefined };
        if (!cmpMeta.platforms) {
            return { tagName };
        }
        compPath = (_c = (_b = cmpMeta === null || cmpMeta === void 0 ? void 0 : cmpMeta.platforms) === null || _b === void 0 ? void 0 : _b.mp) === null || _c === void 0 ? void 0 : _c.path;
        if ((_e = (_d = cmpMeta === null || cmpMeta === void 0 ? void 0 : cmpMeta.platforms) === null || _d === void 0 ? void 0 : _d.mp) === null || _e === void 0 ? void 0 : _e.tagName) {
            tagName = (_f = cmpMeta === null || cmpMeta === void 0 ? void 0 : cmpMeta.platforms) === null || _f === void 0 ? void 0 : _f.mp.tagName;
        }
        if (compPath) {
            compPath =
                compPath.startsWith('/') || compPath.indexOf('://') > 0
                    ? compPath
                    : path.posix.join('/', ctx.wedaRoot || '', `${config_1.materialsDirName}/${cmp.moduleName}`, compPath);
            tagName = `${/^\$/.test(moduleName) ? NAME_MANAGER.mangle(moduleName) : moduleName}-${name}`;
            if (nameMangler) {
                tagName = nameMangler.mangle(tagName);
            }
        }
    }
    else {
        compPath = `plugin://${miniprogramPlugin === null || miniprogramPlugin === void 0 ? void 0 : miniprogramPlugin.name}/${name}`;
        tagName = `${/^\$/.test(moduleName) ? NAME_MANAGER.mangle(moduleName) : moduleName}-${name}`;
        if (nameMangler) {
            tagName = nameMangler.mangle(tagName);
        }
    }
    if (!tagName) {
        tagName = name.toLocaleUpperCase();
    }
    return {
        tagName,
        path: compPath,
    };
}
exports.getWxmlTag = getWxmlTag;
