"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 = exports.normalizeCompositeDependienciesForBuild = void 0;
const path = __importStar(require("path"));
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_1 = require("../util");
const util_2 = 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 lowcode_generator_1 = require("@cloudbase/lowcode-generator");
const templateDir = `${config_1.appTemplateDir}/mp/`;
function normalizeCompositeDependienciesForBuild(lib) {
    lib.dependencies = lib.dependencies || {};
    lib.components.map((cmp) => {
        // populate cmp.materialName
        cmp.materialName = lib.name;
        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 };
        }
    });
    return lib;
}
exports.normalizeCompositeDependienciesForBuild = normalizeCompositeDependienciesForBuild;
async function generateCompLibs(ctx, outDir, mode) {
    const { materialLibs } = ctx;
    // Collection infomation from components to lib meta
    const compositedLibs = materialLibs.filter((lib) => lib.isComposite);
    const reg = new RegExp(`${cals_1.SPINOFF_SUFFIX}$`);
    // #2 Generate composited libs
    await Promise.all(compositedLibs.map(async (lib) => {
        console.log(`Generate composited library ${lib.name}`);
        await Promise.all(lib.components.map(async (cmp) => {
            return generateCompositeComponent({
                ...ctx,
                /**
                 * 此处强行覆盖为 rpx 是为了兼容老的复合组件
                 * $template, 和单独lib构建应受控，跟随应用的配置
                 */
                processCssUnit: lib.name === cals_1.OFFICIAL_COMPONENT_LIB_NAME || reg.test(lib.name) ? 'rpx' : ctx.processCssUnit,
                // 只生成在主目录中，减少冗余
                // rootPath: app.rootPath || '', // 主包是没有 rootPath 的
            }, cmp, outDir, lib.rootPath !== undefined ? lib.rootPath : path.posix.join(config_1.materialsDirName, lib.name), lib.compLibCommonResource, mode);
        }));
    }));
}
async function installMaterials(ctx, outDir, usedMeta, mode = 'inline') {
    let { materialLibs: _materialLibs, isBrowserMpBuilder } = ctx;
    let materialLibs = _materialLibs.filter((lib) => {
        if (!usedMeta) {
            return true;
        }
        return usedMeta.component[lib.name] || usedMeta.action[lib.name];
    });
    // #1 Download uploaded libs
    const localPkg = (0, util_1.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_1.readComponentLibMata)(libDir);
            if (!meta) {
                return true;
            }
            if (meta.version !== lib.version) {
                return true;
            }
        }
        const targetDir = path.join(outDir, config_1.materialsDirName, name);
        if (libUpdated(targetDir, version)) {
            let sourceDir = materialsSrcDir;
            const materialsSrcDirPath = path.join(materialsSrcDir, 'src');
            if (fs.existsSync(materialsSrcDirPath)) {
                sourceDir = materialsSrcDirPath;
                // #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'));
                }
            }
            if (!(name === cals_1.OFFICIAL_LIB_KEY && mode === 'lib')) {
                console.log(`Copying material ${materialId} from ${sourceDir} to ${targetDir}`);
                // #3 copy 组件库代码文件到项目目录
                !isBrowserMpBuilder
                    ? await fs.copy(sourceDir, targetDir, {
                        filter: filterMaterial,
                    })
                    : (0, generateFiles_1.copyRecursiveSync)(sourceDir, targetDir, {
                        filter: filterMaterial,
                    });
            }
        }
        const libMeta = (0, util_1.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
    materialLibs.forEach((lib) => {
        lib.components = lib.components.filter((comp) => {
            var _a, _b;
            if (!usedMeta) {
                return true;
            }
            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);
        });
        normalizeCompositeDependienciesForBuild(lib);
    });
    ctx.materialLibs = materialLibs;
    await generateCompLibs(ctx, outDir, mode);
}
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(compositeCtx, compositedComp, lowcalWedaRoot, componentLibRoot, compLibCommonResource, mode = 'inline') {
    var _a;
    const { materialName } = compositedComp;
    const componentRelativeDir = path.posix.join(componentLibRoot, compositedComp.name);
    const componentDir = path.join(lowcalWedaRoot, componentLibRoot, 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_2.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}}';
        }
    }, mode);
    // 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_1.generateLowcodeImportor)(codes);
    const pageFileData = {
        'index.js': {
            relativeWedaRoot: path.posix.relative(path.posix.join('/', componentRelativeDir), '/') || '.',
            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_2.createEventHandlers)(compositeCtx, componentInstances, weapps_core_1.COMPONENT_API_PREFIX, {
                listeners: compositedComp.listeners,
                id: '__comp__',
            }),
            emitEvents: (compositedComp.emitEvents || []).map((evt) => evt.eventName),
            widgetProps: (0, util_2.createWidgetProps)(compositeCtx, componentInstances),
            jsonSchemaType2jsClass: mp_1.jsonSchemaType2jsClass,
            key: `${materialName}:${compositedComp.name}`,
            dataBinds: (0, util_2.createDataBinds)(compositeCtx, componentInstances),
            debug: !compositeCtx.isProduction,
            formEvents: Object.keys(formEvents).length > 0 ? formEvents : null,
            config: compositedComp.compConfig,
            importor,
            datasetProfile: (0, util_1.JsonToStringWithVariableName)((0, lowcode_generator_1.generateDynamicDataset)(compositedComp.dataset || {}), {
                EOL: true,
            }),
            query: (0, util_2.createTemplateQuery)(compositeCtx, (_a = compositedComp.dataset) === null || _a === void 0 ? void 0 : _a.query) || {},
            eventFlows: (0, util_2.createTemplateEventFlows)(compositeCtx, compositedComp.eventFlows) || [],
            nativeMode: mode === 'lib' ? 1 : 0,
        },
        'index.json': {
            usingComponents: Object.entries(usingComponents).reduce((map, [key, value]) => {
                if (new RegExp(`^${path.posix.join('/', compositeCtx.wedaRoot || '', '\\w')}`).test(value)) {
                    map[key] = path.posix.relative(path.posix.join('/', compositeCtx.wedaRoot || '', componentRelativeDir), value);
                }
                else {
                    map[key] = value;
                }
                return map;
            }, {}),
            componentPlaceholder: mode === 'lib' ? (0, wxml_1.generateComponentPlaceholder)(usingComponents) : undefined,
            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_2.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, mode === 'lib' ? true : false);
    });
    // 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, mode = 'inline') {
    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) {
        const libRootInMiniprogram = materialLib.name === cals_1.OFFICIAL_LIB_KEY && mode === 'lib'
            ? cals_1.OFFICIAL_LIB_MP_NPM_PACKAGENAME
            : path.posix.join('/', ctx.wedaRoot || '', (materialLib === null || materialLib === void 0 ? void 0 : materialLib.rootPath)
                ? materialLib === null || materialLib === void 0 ? void 0 : materialLib.rootPath
                : path.posix.join(`${config_1.materialsDirName}/${cmp.moduleName}`));
        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(libRootInMiniprogram, 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;
