"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.downloadAssets = exports.generateWebpackWebDevServerFile = exports.getMaterialNodeModulesPathList = exports.installDependencies = exports.downloadDependencies = exports.downloadAndInstallDependencies = exports.getWebpackWebBuildParams = exports.getPageName = exports.getHomePageInstance = exports.getMainAppDataByList = exports.downloadAndWriteTabBarIcon = exports.generateKboneTabBarConfig = exports.generateWebpackWebBuildParamsFile = exports.fixAppJson = exports.OUTPUT_DIR = exports.PERSISTENT_DEPENDIENCES_MAP = void 0;
const path_1 = __importDefault(require("path"));
const fs_extra_1 = __importDefault(require("fs-extra"));
const lodash_1 = require("lodash");
const util_1 = require("../util");
const axios_1 = __importDefault(require("axios"));
const compressing_1 = __importDefault(require("compressing"));
const cross_spawn_1 = __importDefault(require("cross-spawn"));
const weapps_core_1 = require("@cloudbase/lowcode-generator/lib/weapps-core");
const config_1 = require("../config");
const common_1 = require("../types/common");
const common_2 = require("../util/common");
const types_1 = require("../../types");
const generateFiles_1 = require("../util/generateFiles");
exports.PERSISTENT_DEPENDIENCES_MAP = {};
exports.OUTPUT_DIR = 'preview';
async function fixAppJson(appBuildDir) {
    const appJsonPath = path_1.default.resolve(appBuildDir, 'dist/mp/app.json');
    if (!fs_extra_1.default.existsSync(appJsonPath)) {
        return;
    }
    const appJson = await fs_extra_1.default.readJSON(appJsonPath);
    appJson.subpackages = appJson.subpackages.map((config) => {
        config.pages = config.pages.map((pagePath) => {
            const pagePathArr = pagePath.split('/');
            if (pagePathArr.length === 4 && pagePathArr[1] === config.root) {
                pagePathArr.splice(1, 1);
                return pagePathArr.join('/');
            }
            return pagePath;
        });
        return config;
    });
    await fs_extra_1.default.writeFile(appJsonPath, JSON.stringify(appJson, null, 2));
}
exports.fixAppJson = fixAppJson;
async function generateWebpackWebBuildParamsFile({ appId, allAppDataList, appBuildDir, publicPath, mode, buildTypeList, assets = [], }) {
    let mainAppData = getMainAppDataByList(allAppDataList);
    let extraDefine = {
        'process.env.historyType': `"${mainAppData.historyType || types_1.HISTORY_TYPE.BROWSER}"`,
    };
    const params = getWebpackWebBuildParams(appId, appBuildDir, publicPath, mode, buildTypeList, extraDefine, assets);
    const webpackConfigPath = path_1.default.resolve(appBuildDir, './webpack/webpack.web.prod.js');
    const paramsString = JSON.stringify(params, null, 2);
    const webpackConfigContent = `const params = ${paramsString};\nmodule.exports = require('./web.prod.js')(params);`;
    await (0, generateFiles_1.writeFile)(webpackConfigPath, webpackConfigContent);
    return webpackConfigPath;
}
exports.generateWebpackWebBuildParamsFile = generateWebpackWebBuildParamsFile;
async function generateKboneTabBarConfig(mpConfig, appBuildDir) {
    mpConfig.appExtraConfig = mpConfig.appExtraConfig || {};
    if (mpConfig.appExtraConfig.tabBar) {
        if (mpConfig.appExtraConfig.tabBar.list) {
            await Promise.all(mpConfig.appExtraConfig.tabBar.list.map(async (item) => {
                if (item.iconPath) {
                    item.iconPath = await downloadAndWriteTabBarIcon(item.iconPath, item.pagePath, appBuildDir, 'iconPath');
                }
                if (item.selectedIconPath) {
                    item.selectedIconPath = await downloadAndWriteTabBarIcon(item.selectedIconPath, item.pagePath, appBuildDir, 'selectedIconPath');
                }
            }));
        }
    }
}
exports.generateKboneTabBarConfig = generateKboneTabBarConfig;
async function downloadAndWriteTabBarIcon(iconPath, pagePath, appBuildDir, fileName) {
    console.log('开始下载文件', iconPath);
    const extname = path_1.default.extname(iconPath);
    const relativePath = `images_tabBar/${pagePath}/${fileName}${extname}`;
    const fileFullPath = path_1.default.resolve(appBuildDir, `dist/mp/${relativePath}`);
    await fs_extra_1.default.ensureFile(fileFullPath);
    const writer = fs_extra_1.default.createWriteStream(fileFullPath);
    const response = await (0, axios_1.default)({
        method: 'get',
        url: iconPath,
        responseType: 'stream',
    });
    response.data.pipe(writer);
    return new Promise((resolve, reject) => {
        writer.on('finish', () => {
            console.log('下载成功', iconPath);
            // copy 一份到web
            // fs.copy(
            //   fileFullPath,
            //   path.resolve(appBuildDir, `preview/${relativePath}`)
            // )
            resolve(relativePath);
        });
        writer.on('error', () => {
            console.error('下载失败', iconPath);
            reject();
        });
    });
}
exports.downloadAndWriteTabBarIcon = downloadAndWriteTabBarIcon;
function getMainAppDataByList(allAppDataList) {
    return allAppDataList.find((item) => !item.rootPath);
}
exports.getMainAppDataByList = getMainAppDataByList;
// 获取设置的 home 页面
function getHomePageInstance(pageInstanceList) {
    let target = pageInstanceList[0];
    (0, weapps_core_1.loopDealWithFn)(pageInstanceList, (pageInstance) => {
        if (pageInstance.isHome) {
            target = pageInstance;
            return pageInstance;
        }
    });
    return target;
}
exports.getHomePageInstance = getHomePageInstance;
// 获取页面名字
function getPageName(name) {
    return `${name}`;
}
exports.getPageName = getPageName;
function getWebpackWebBuildParams(appId, appBuildDir, publicPath = '/', mode = common_1.WebpackModeType.NONE, buildTypeList = [common_1.BuildType.WEB], extraDefine = {}, assets = []) {
    return {
        context: appBuildDir,
        mode: mode !== common_1.WebpackModeType.PRODUCTION ? 'development' : mode,
        watch: false,
        entry: path_1.default.resolve(appBuildDir, 'src/index.jsx'),
        output: {
            path: path_1.default.resolve(appBuildDir, exports.OUTPUT_DIR),
            filename: '[name].[hash].bundle.js',
            chunkFilename: '[name].[contenthash].chunk.js',
            publicPath: buildTypeList.includes(common_1.BuildType.APP) || buildTypeList.includes(common_1.BuildType.ADMIN_PORTAL) ? '' : publicPath,
            pathinfo: false,
            // clean: mode === WebpackModeType.PRODUCTION,
        },
        htmlTemplatePath: path_1.default.resolve(appBuildDir, './index.html'),
        externals: {
            react: 'window.React',
            'react-dom': 'window.ReactDOM',
            mobx: 'window.mobx',
            '@cloudbase/js-sdk': 'window.cloudbase',
            '@cloudbase/weda-cloud-sdk/dist/h5': 'window.CloudSDK',
            '@cloudbase/weda-cloud-sdk': 'window.CloudSDK',
            '@cloudbase/weda-client': 'window.WedaClientSDK',
            '@zxing/library': 'window.ZXing',
            '@cloudbase/lowcode-render': 'window["weda-render"]',
        },
        resolveModules: [path_1.default.resolve(appBuildDir), 'node_modules'],
        definePlugin: {
            'process.env.buildType': `"${buildTypeList[0]}"`,
            ...extraDefine,
        },
        devtool: ['app-nvzcvt10', 'app-msa2ihs9', 'app-PMoFiTuX'].includes(appId)
            ? 'source-map'
            : mode !== common_1.WebpackModeType.PRODUCTION
                ? 'eval'
                : false,
    };
}
exports.getWebpackWebBuildParams = getWebpackWebBuildParams;
async function downloadAndInstallDependencies(dependencies = [], materialsDir, installOptions = {}) {
    const localPkg = (0, util_1.getCurrentPackageJson)();
    await Promise.all(dependencies.map(async (item) => {
        const { name, version, srcZipUrl } = item;
        const materialNameVersion = `${name}@${version}`;
        const targetDir = path_1.default.join(materialsDir, materialNameVersion);
        // 当前本地目录是素材库的时候，直接用本地的
        if (localPkg && localPkg.name === name && localPkg.version === version) {
            console.log('当前本地目录是素材库的时候，无需安装', materialNameVersion);
            return;
        }
        // 如果需要下载素材
        if (!(await fs_extra_1.default.pathExists(targetDir))) {
            const matched = srcZipUrl.match(/\/(cg-.*?)\//);
            const { appBuildDir } = (0, util_1.getCompileDirs)('app');
            if ((matched === null || matched === void 0 ? void 0 : matched[1]) && fs_extra_1.default.existsSync(path_1.default.resolve(appBuildDir, `.component_cache/web/${matched[1]}@${version}`))) {
                console.log(`link ${name}@${version} ...`);
                await fs_extra_1.default.symlink(path_1.default.resolve(appBuildDir, `.component_cache/web/${matched[1]}@${version}`), targetDir, 'dir');
                // await fs.copy(
                //   path.resolve(
                //     appBuildDir,
                //     `.component_cache/web/${matched[1]}@${version}`
                //   ),
                //   targetDir,
                //   {
                //     filter: function (src, dest) {
                //       const path = src.split('/');
                //       return !junk.is(path[path.length - 1]);
                //     },
                //   }
                // );
            }
            else {
                console.log(`下载${name}@${version} ...`);
                await downloadDependencies(targetDir, srcZipUrl);
            }
        }
        // 同步依赖
        // const packageJson = await fs.readJson(
        //   path.join(targetDir, 'package.json')
        // );
        // item.dependencies = packageJson.dependencies || {};
    }));
    await Promise.all(dependencies.map(async (item) => {
        const { name, version, srcZipUrl } = item;
        const materialNameVersion = `${name}@${version}`;
        const targetDir = path_1.default.join(materialsDir, materialNameVersion);
        console.log(`处理${name}@${version}依赖 ...`);
        await installDependencies(targetDir, {
            ...installOptions,
            isDependence: true,
            ignoreInstall: (0, common_2.isOfficialComponentLib)(name, version) || (installOptions === null || installOptions === void 0 ? void 0 : installOptions.ignoreInstall),
            dependenceMeta: {
                name,
                version,
                downloadUrl: srcZipUrl,
            },
        });
    }));
}
exports.downloadAndInstallDependencies = downloadAndInstallDependencies;
async function downloadDependencies(targetDir, srcZipUrl) {
    const isExist = fs_extra_1.default.existsSync(path_1.default.join(targetDir, 'package.json'));
    if (isExist || !srcZipUrl) {
        return;
    }
    try {
        let response = await (0, axios_1.default)({
            url: srcZipUrl,
            responseType: 'stream',
            // proxy: false
        });
        await fs_extra_1.default.ensureDir(targetDir);
        // let download = spawn(
        //   'curl',
        //   ['-fsSL', srcZipUrl, '-o', `${targetDir}.zip`],
        //   {
        //     stdio: 'inherit',
        //   }
        // );
        // await promisifyProcess(download);
        const tag = `uncompress ${srcZipUrl}`;
        console.time(tag);
        await compressing_1.default.zip.uncompress(response.data, targetDir);
        // let unzip = spawn(
        //   'unzip',
        //   ['-q', '-o', `${targetDir}.zip`, '-d', targetDir],
        //   {
        //     stdio: 'inherit',
        //   }
        // );
        // await promisifyProcess(unzip);
        // await fs.remove(`${targetDir}.zip`);
        console.timeEnd(tag);
    }
    catch (e) {
        console.error(`Fail to download weapps material package ${srcZipUrl}`, e);
        throw e;
    }
}
exports.downloadDependencies = downloadDependencies;
// TODO use yarn if installed
async function installDependencies(targetDir, options = {}) {
    var _a;
    let yarnExists = false;
    try {
        let { stdout, status } = cross_spawn_1.default.sync('yarn', ['-v']);
        let str = stdout.toString();
        if (!status && Number((_a = str.split('.')) === null || _a === void 0 ? void 0 : _a[0]) <= 1) {
            yarnExists = true;
        }
    }
    catch (e) { }
    const packageJsonPath = path_1.default.resolve(targetDir, 'package.json');
    /**
     * 无 cacheMeta 或 cacheMeta.once 时 遵循 options?.ignoreInstall 配置
     * 否则认为文件发生了更改，应该忽略参数强制安装
     */
    const cacheMeta = generateFiles_1.generatedFileContents[packageJsonPath];
    const isPkgModify = !cacheMeta || cacheMeta.once ? false : cacheMeta.modify;
    if ((options === null || options === void 0 ? void 0 : options.ignoreInstall) && fs_extra_1.default.existsSync(path_1.default.join(targetDir, 'node_modules')) && !isPkgModify) {
        console.log(`ignore install dependencies in ${targetDir}`);
        return;
    }
    // const isExist = fs.existsSync(path.join(targetDir, 'package-lock.json'))
    // 是否安装最新的
    let packageName = options.packageName || '';
    if (packageName && options.latest) {
        packageName = `${packageName}@latest`;
    }
    console.log(`Installing dependencies in ${targetDir}`);
    const operationTag = `----------------  ${yarnExists ? 'yarn' : 'npm'} Install dependencies`;
    console.time(operationTag);
    const registry = `--registry=${process.env.NPM_REGISTRY || config_1.npmRegistry}`;
    const npmOptions = ['--prefer-offline', '--no-audit', '--progress=false', registry];
    if (options === null || options === void 0 ? void 0 : options.dependenceMeta) {
        npmOptions.push('--production');
        const { name, version } = options.dependenceMeta;
        if (!fs_extra_1.default.existsSync(path_1.default.join(targetDir, 'node_modules'))) {
            exports.PERSISTENT_DEPENDIENCES_MAP[`${name}@${version}`] = {
                ...options === null || options === void 0 ? void 0 : options.dependenceMeta,
                source: targetDir,
            };
        }
    }
    // 云端构建, 选用 npm
    const installProcessOptions = {
        cwd: targetDir,
        // NODE_ENV="production"时，devDependencies里的包不会下载，兼容h5在线编译
        env: { ...process.env, NODE_ENV: '' },
        stdio: 'inherit',
    };
    let installprocess;
    // TODO: install 失败 应该终止进程
    if (yarnExists && (options === null || options === void 0 ? void 0 : options.runtime) !== types_1.RUNTIME.CI) {
        const addPackage = packageName ? ['add', packageName] : [];
        installprocess = cross_spawn_1.default.sync('yarn', [...addPackage, registry], installProcessOptions);
    }
    else {
        installprocess = cross_spawn_1.default.sync('npm', ['install', packageName, ...npmOptions], installProcessOptions);
    }
    // TODO: 确认 process.status 语义来判断是否标识进程正常退出
    if (installprocess.status) {
        throw new Error(`安装依赖失败 ${installprocess.error || ''}`);
    }
    fixNodeModules(targetDir, options === null || options === void 0 ? void 0 : options.fixNodeModulesMap);
    try {
        await fs_extra_1.default.remove(path_1.default.join(path_1.default.join(targetDir, 'package-lock.json')));
        await fs_extra_1.default.remove(path_1.default.join(path_1.default.join(targetDir, 'yarn.lock')));
    }
    catch (e) { }
    console.timeEnd(operationTag);
}
exports.installDependencies = installDependencies;
function fixNodeModules(projDir, options = { mobx: false, '@cloudbase/js-sdk': false }) {
    const { mobx = false, ['@cloudbase/js-sdk']: jsSDK = false } = options;
    if (mobx) {
        // # fix mobx/package.json: "main": "lib/index.js" -> "main": "lib/index.js"
        const mobxPackageFile = path_1.default.join(projDir, 'node_modules', 'mobx/package.json');
        if (fs_extra_1.default.existsSync(mobxPackageFile)) {
            const mobxPackageFileContent = fs_extra_1.default.readJSONSync(mobxPackageFile);
            if (fs_extra_1.default.existsSync(path_1.default.join(projDir, 'node_modules', 'mobx/lib/mobx.min.js'))) {
                mobxPackageFileContent.main = 'lib/mobx.min.js';
                fs_extra_1.default.writeJSONSync(mobxPackageFile, mobxPackageFileContent);
            }
        }
    }
    if (jsSDK) {
        const scriptPath = path_1.default.resolve(projDir, 'node_modules', '@cloudbase/weda-cloud-sdk/scripts/fix-wx-none-private.js');
        if (fs_extra_1.default.existsSync(scriptPath)) {
            const fix = require(scriptPath);
            fix();
        }
    }
}
function getMaterialNodeModulesPathList(dependencies = [], materialsDir, base) {
    const localPkg = (0, util_1.getCurrentPackageJson)();
    return dependencies.map(({ name, version }) => {
        const nameVersion = `${name}@${version}`;
        let target = '';
        if (localPkg && localPkg.name === name && localPkg.version === version) {
            console.log('当前本地目录是素材库的时候，直接使用当前目录的 node_modules', nameVersion);
            target = path_1.default.join(process.cwd(), 'node_modules');
        }
        else {
            target = path_1.default.join(materialsDir, nameVersion, 'node_modules');
        }
        return base ? path_1.default.relative(base, target) : target;
    });
}
exports.getMaterialNodeModulesPathList = getMaterialNodeModulesPathList;
// 生成devServer 核心依赖
async function generateWebpackWebDevServerFile({ appBuildDir, buildTypeList }) {
    const dest = path_1.default.resolve(appBuildDir, `./webpack/devServer.js`);
    const template = await fs_extra_1.default.readFile(path_1.default.resolve(config_1.appTemplateDir, './webpack/devServer.js'), {
        encoding: 'utf8',
    });
    const jsContent = (0, lodash_1.template)(template, {
        interpolate: /<%=([\s\S]+?)%>/g,
    })({
        isApp: buildTypeList.includes(common_1.BuildType.APP),
        isAdminPortal: (0, common_1.buildAsAdminPortalByBuildType)(buildTypeList),
    });
    await fs_extra_1.default.ensureFile(dest);
    await fs_extra_1.default.writeFile(dest, jsContent);
}
exports.generateWebpackWebDevServerFile = generateWebpackWebDevServerFile;
// 下载js 文件
async function downloadAssets(targetDir, assetUrl) {
    const isExist = fs_extra_1.default.existsSync(path_1.default.join(targetDir, 'package.json'));
    if (isExist || !assetUrl) {
        return;
    }
    const [err, response] = await (0, util_1.promiseWrapper)((0, axios_1.default)({
        url: assetUrl,
        responseType: 'stream',
        // proxy: false
    }));
    if (err) {
        console.error(`Fail to download weapps material package ${assetUrl}`, err);
        throw err;
    }
    await fs_extra_1.default.ensureDir(targetDir);
    const filename = (0, common_2.getFileNameByUrl)(assetUrl);
    const targetPath = path_1.default.resolve(targetDir, `./${filename}`);
    const writer = fs_extra_1.default.createWriteStream(targetPath);
    response.data.pipe(writer);
    return new Promise((resolve, reject) => {
        writer.on('finish', () => {
            console.log('下载成功', assetUrl);
            fs_extra_1.default.copy(targetDir, path_1.default.resolve(targetDir, '../preview'));
            resolve(targetPath);
        });
        writer.on('error', () => {
            console.error('下载失败', assetUrl);
            reject();
        });
    });
}
exports.downloadAssets = downloadAssets;
