"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.handleMixMaterials = exports.handleMixMode = void 0;
const path_1 = __importDefault(require("path"));
const fs_extra_1 = __importStar(require("fs-extra"));
const mp_1 = require("../util/mp");
const plugin_1 = require("./plugin");
const lodash_1 = require("lodash");
const chalk_1 = __importDefault(require("chalk"));
const generateFiles_1 = require("../util/generateFiles");
const webpack_1 = require("../service/webpack");
// 将 BUILD 目录往混合模式移动
async function handleMixMode({ buildContext, apps = [], miniprogramRoot, plugins = [], ignoreInstall, }) {
    const { projDir: generateMpPath, endpointType } = buildContext;
    // await handleMainApp()
    // await handleAppPages()
    await handleSubApps();
    // await handleAppJson()
    // await handlePkgJson()
    await (0, webpack_1.installDependencies)(miniprogramRoot, {
        ignoreInstall,
        fixNodeModulesMap: { mobx: true, '@cloudbase/js-sdk': endpointType !== 'tcb-api' },
    });
    await handlePlugins();
    // 复制框架公用内容
    async function handleMainApp() {
        // 可以独立删除的
        const aloneDirs = ['common', 'app', 'lowcode', 'materials'];
        // 与主程序混合不能主动删除的
        const dirs = aloneDirs;
        await Promise.all(dirs.map(async (dirname) => {
            const srcDir = path_1.default.join(miniprogramRoot, dirname);
            if (await fs_extra_1.default.pathExists(srcDir)) {
                const distDir = path_1.default.join(generateMpPath, dirname);
                if (aloneDirs.includes(dirname)) {
                    await fs_extra_1.default.remove(distDir);
                }
                await fs_extra_1.default.copy(srcDir, distDir);
            }
        }));
    }
    // 复制主包的页面，需要判断是否有冲突
    async function handleAppPages() {
        // 需要特殊处理的
        const srcDir = path_1.default.join(miniprogramRoot, 'pages');
        const distDir = path_1.default.join(generateMpPath, 'pages');
        const pageList = await fs_extra_1.default.readdir(srcDir);
        await Promise.all(pageList.map(async (page) => {
            const srcPageDir = path_1.default.join(srcDir, page);
            const srcDistDir = path_1.default.join(distDir, page);
            if (await fs_extra_1.default.pathExists(srcDistDir)) {
                console.log(chalk_1.default.yellow(`【混合模式】 WeApps 中的 pages/${page} 与小程序 pages/${page} 重复，会以 WeApps 的为主`));
            }
            await fs_extra_1.default.copy(srcPageDir, srcDistDir);
        }));
    }
    async function handleSubApps() {
        let modifiedAppJson = false;
        const rootAppJosnPath = path_1.default.join(miniprogramRoot, 'app.json');
        let rootAppJosn = await fs_extra_1.default.readJSON(rootAppJosnPath);
        let modifiedPackageJosn = false;
        const rootPackageJosnPath = path_1.default.join(miniprogramRoot, 'package.json');
        let rootPackageJson = fs_extra_1.default.existsSync(rootPackageJosnPath)
            ? await fs_extra_1.default.readJson(rootPackageJosnPath)
            : {
                name: 'WeDa-app',
                version: '1.0.0',
            };
        let mergeDependencies = {};
        await Promise.all(apps
            .filter((app) => app.rootPath)
            .map(async (app) => {
            const subAppPath = path_1.default.join(miniprogramRoot, app.rootPath || '');
            // 复制整个子包
            // 新模式下已经生成，感觉无需进行复制 @royhyang
            // const distDir = path.join(generateMpPath, app.rootPath || '')
            // await fs.copy(subAppPath, distDir, { overwrite: true })
            const appJsonPath = path_1.default.join(subAppPath, 'app.json');
            if (fs_extra_1.default.existsSync(appJsonPath)) {
                let appJson = await fs_extra_1.default.readJson(appJsonPath);
                if (appJson) {
                    let { subpackages = [] } = rootAppJosn;
                    const find = subpackages.find((item) => item.root == app.rootPath);
                    if (find) {
                        find.pages = appJson.pages;
                    }
                    else {
                        if (!rootAppJosn.subpackages) {
                            rootAppJosn.subpackages = [];
                        }
                        rootAppJosn.subpackages.push({
                            root: app.rootPath,
                            pages: appJson.pages,
                        });
                    }
                    modifiedAppJson = true;
                }
            }
            const packageJosnPath = path_1.default.join(subAppPath, 'package.json');
            if (fs_extra_1.default.existsSync(packageJosnPath)) {
                mergeDependencies = {
                    ...mergeDependencies,
                    ...(await (0, mp_1.mergePackageDependiences)(mergeDependencies, await fs_extra_1.default.readJson(packageJosnPath))),
                };
                modifiedPackageJosn = true;
            }
            await Promise.all([
                'app.json',
                'app.js',
                'app.wxss',
                'project.config.json',
                'package.json',
                'node_modules',
                'miniprograme_npm',
            ].map((name) => {
                let clearPath = path_1.default.join(subAppPath, name);
                return name.includes('.') ? (0, generateFiles_1.removeFile)(clearPath) : (0, generateFiles_1.cleanDir)(clearPath, []);
            }));
        }));
        if (modifiedAppJson) {
            await (0, fs_extra_1.writeFile)(rootAppJosnPath, JSON.stringify(rootAppJosn, undefined, 2));
        }
        if (modifiedPackageJosn) {
            await (0, fs_extra_1.writeFile)(rootPackageJosnPath, JSON.stringify({
                ...rootPackageJson,
                ...(0, mp_1.mergePackageDependiences)(mergeDependencies, rootPackageJson), // 主包优先
            }, undefined, 2));
        }
    }
    // 复制插件
    async function handlePlugins() {
        const mpPlugins = (await (0, plugin_1.getPluginType)(generateMpPath, plugins)).filter((item) => item.type === 'mp');
        return Promise.all(mpPlugins.map(async (plugin) => {
            const pluginModule = plugin.module;
            const pluginNodeModuleDir = path_1.default.resolve(generateMpPath, 'node_modules', pluginModule);
            const pluginPkgJson = await fs_extra_1.default.readJson(path_1.default.join(pluginNodeModuleDir, 'package.json'));
            const { pluginName } = pluginPkgJson;
            const pluginDir = path_1.default.join(miniprogramRoot, pluginName);
            const distDir = path_1.default.join(generateMpPath, pluginName);
            await fs_extra_1.default.copy(pluginDir, distDir, { overwrite: true });
        }));
    }
    async function handleAppJson() {
        const baseAppJsonPath = path_1.default.join(generateMpPath, 'app.json');
        const mergeAppJsonPath = path_1.default.join(miniprogramRoot, 'app.json');
        await (0, mp_1.mergePages)(baseAppJsonPath, mergeAppJsonPath);
        await (0, mp_1.mergeSubPackages)(baseAppJsonPath, mergeAppJsonPath);
    }
    async function handlePkgJson() {
        const basePkgJsonPath = path_1.default.join(generateMpPath, 'package.json');
        const mergePkgJsonPath = path_1.default.join(miniprogramRoot, 'package.json');
        await (0, mp_1.mergePackageJson)(basePkgJsonPath, mergePkgJsonPath);
    }
}
exports.handleMixMode = handleMixMode;
// 子模式则清理未使用的组件库
async function handleMixMaterials(projDir, apps, appUsedComps, compositedLibs) {
    return Promise.all(apps.map(async (app) => {
        var _a;
        const rootPath = app.rootPath || '';
        const materialsDirPath = path_1.default.join(projDir, rootPath, 'materials');
        const usedComps = ((_a = appUsedComps.find((item) => item.rootPath === rootPath)) === null || _a === void 0 ? void 0 : _a.usedComps) || {};
        const materialsLib = await readDirs(materialsDirPath);
        // 清理未使用的组件库
        const cleanLibs = (0, lodash_1.difference)(materialsLib, Object.keys(usedComps));
        await removeDirs(cleanLibs.map((libName) => path_1.default.join(materialsDirPath, libName)));
        // 清理未使用的组件
        await Promise.all(Object.keys(usedComps).map(async (libName) => {
            // 只去处理复合组件
            if (!compositedLibs.find((item) => item.name === libName)) {
                return;
            }
            const libComponents = usedComps[libName];
            const materialsLibComps = await readDirs(path_1.default.join(materialsDirPath, libName));
            const cleanComps = (0, lodash_1.difference)(materialsLibComps, Array.from(libComponents));
            await removeDirs(cleanComps.map((compName) => path_1.default.join(materialsDirPath, libName, compName)));
        }));
    }));
}
exports.handleMixMaterials = handleMixMaterials;
async function removeDirs(dirs) {
    return Promise.all(dirs.map((dir) => {
        console.log('【MIX MODE 清理】', dir);
        return fs_extra_1.default.remove(dir);
    }));
}
// 只返回文件夹
async function readDirs(dirPath) {
    const isDirectory = (source) => (0, fs_extra_1.lstatSync)(source).isDirectory();
    return ((await fs_extra_1.default.readdir(dirPath)) || []).filter((name) => isDirectory(path_1.default.join(dirPath, name)));
}
