"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const fs_1 = __importDefault(require("fs"));
const path_1 = __importDefault(require("path"));
const FileUtils_1 = __importDefault(require("../utils/FileUtils"));
const MD5Utils_1 = __importDefault(require("../utils/MD5Utils"));
const PackageScript_1 = require("./PackageScript");
const START_VERSION = 1000;
const VERSION_SUPPORT = 50;
function readExistPackageRecords(versionCacheDir) {
    const versions = [];
    const versionFiles = fs_1.default.readdirSync(versionCacheDir);
    versionFiles.forEach(versionFile => {
        const versionFilePath = path_1.default.join(versionCacheDir, versionFile);
        const stat = fs_1.default.statSync(versionFilePath);
        if (stat.isDirectory())
            return;
        const versionString = path_1.default.basename(versionFile, path_1.default.extname(versionFile));
        const version = parseInt(versionString);
        versions.push(version);
    });
    return versions.sort((a, b) => a - b).slice(-VERSION_SUPPORT);
}
function readPackageRecord(version, versionCacheDir) {
    const infoFilePath = path_1.default.join(versionCacheDir, `${version}.json`);
    if (!fs_1.default.existsSync(infoFilePath))
        return null;
    const subpackageInfoContent = fs_1.default.readFileSync(infoFilePath);
    const info = JSON.parse(subpackageInfoContent.toString());
    return info;
}
function writePackageRecord(version, record, versionCacheDir) {
    const content = JSON.stringify(record);
    const infoFilePath = path_1.default.join(versionCacheDir, `${version}.json`);
    FileUtils_1.default.mkdir(path_1.default.dirname(infoFilePath));
    fs_1.default.writeFileSync(infoFilePath, content);
}
function loadMainConfig(url) {
    const configCache = path_1.default.join(process.env.HOME || process.env.USERPROFILE, '.sgp', 'config', `${MD5Utils_1.default.md5(url)}`, `subgame_config.json`);
    if (fs_1.default.existsSync(configCache)) {
        const mainConfig = JSON.parse(fs_1.default.readFileSync(configCache).toString());
        return mainConfig;
    }
    return [];
}
function loadPackageConfig(url, key) {
    const configCache = path_1.default.join(process.env.HOME || process.env.USERPROFILE, '.sgp', 'config', `${MD5Utils_1.default.md5(url)}`, `subgame_config_${key}.json`);
    if (fs_1.default.existsSync(configCache)) {
        const packageConfig = JSON.parse(fs_1.default.readFileSync(configCache).toString());
        return packageConfig;
    }
    return null;
}
function writeMainConfig(url, mainConfigs) {
    const configCacheDir = path_1.default.join(process.env.HOME || process.env.USERPROFILE, '.sgp', 'config', `${MD5Utils_1.default.md5(url)}`);
    FileUtils_1.default.mkdir(configCacheDir);
    fs_1.default.writeFileSync(path_1.default.join(configCacheDir, `subgame_config.json`), JSON.stringify(mainConfigs));
}
function writePackageConfig(url, key, packageConfig) {
    const configCacheDir = path_1.default.join(process.env.HOME || process.env.USERPROFILE, '.sgp', 'config', `${MD5Utils_1.default.md5(url)}`);
    FileUtils_1.default.mkdir(configCacheDir);
    fs_1.default.writeFileSync(path_1.default.join(configCacheDir, `subgame_config_${key}.json`), JSON.stringify(packageConfig));
}
function PackageAndroid(projectDir, key, frameworkVersion, mode, url, xxtea, zipCompressJs, isolate = false) {
    return __awaiter(this, void 0, void 0, function* () {
        console.log(`-----------------------------------------------------Handle package [${key}] start-----------------------------------------------------`);
        const outputDir = path_1.default.join(projectDir, 'build', 'subgame', 'android');
        console.log(`Make package [${key}] zip dir: ${outputDir}`);
        FileUtils_1.default.mkdir(outputDir);
        const versionCacheDir = path_1.default.join(projectDir, 'version', key, mode);
        console.log(`Make package [${key}] info dir: ${versionCacheDir}`);
        FileUtils_1.default.mkdir(versionCacheDir);
        const buildDir = path_1.default.join(projectDir, 'build', 'jsb-default');
        const bundleDir = path_1.default.join(buildDir, 'assets', key);
        (0, PackageScript_1.PackageScript)(key, buildDir, isolate, xxtea, zipCompressJs);
        const mainConfigs = loadMainConfig(url);
        if (!mainConfigs)
            throw new Error(`load main config fail`);
        const existVersions = readExistPackageRecords(versionCacheDir);
        const haveExistVersion = existVersions && existVersions.length;
        const config = loadPackageConfig(url, key) || { version: START_VERSION, packages: [] };
        const previousVersion = config.version;
        const previousRecord = haveExistVersion ? readPackageRecord(previousVersion, versionCacheDir) : { md5: [] };
        console.log(`Package [${key}] previous version: ${previousVersion}`);
        const md5 = MD5Utils_1.default.md5Dir(bundleDir, null);
        const md5Compare = MD5Utils_1.default.md5Compare(md5, previousRecord.md5);
        console.log(`Package [${key}] compare with last: added=${md5Compare.added.length}, deleted:${md5Compare.deleted.length}, same:${md5Compare.same.length}, changed:${md5Compare.changed.length}`);
        const packageResult = {
            project: projectDir,
            key, frameworkVersion, mode, url, xxtea, zipCompressJs, isolate,
            packageVersion: previousVersion,
            supportVersion: existVersions,
            added: md5Compare.added.length,
            changed: md5Compare.changed.length,
            deleted: md5Compare.deleted.length,
            size: -1
        };
        if (md5Compare.changed.length || md5Compare.added.length) {
            console.log(`Package [${key}] changed`);
            const zipCacheOutputDir = path_1.default.join(outputDir, 'cache');
            console.log(`Make package [${key}] zip cache dir: ${zipCacheOutputDir}`);
            FileUtils_1.default.rm(zipCacheOutputDir);
            FileUtils_1.default.mkdir(zipCacheOutputDir);
            const packages = [];
            const newVersion = previousVersion + 1;
            for (const versionItem of existVersions) {
                console.log(`Pick package [${key}] assets for version ${versionItem} to ${newVersion}`);
                const versionInfo = readPackageRecord(versionItem, versionCacheDir);
                if (!versionInfo) {
                    console.warn(`ackage [${key}] skip exits version ${versionItem}, no version info.`);
                    continue;
                }
                const versionCompareResult = MD5Utils_1.default.md5Compare(md5, versionInfo.md5);
                console.log(`Package [${key}] compare with version ${versionItem}: added=${versionCompareResult.added.length}, deleted:${versionCompareResult.deleted.length} , same:${versionCompareResult.same.length}, changed:${versionCompareResult.changed.length}`);
                const files = versionCompareResult.changed.concat(versionCompareResult.added);
                const zipCacheDir = path_1.default.join(zipCacheOutputDir, `${versionItem}_${newVersion}`);
                FileUtils_1.default.mkdir(zipCacheDir);
                files.forEach(value => {
                    const outPath = path_1.default.join(zipCacheDir, value.path);
                    FileUtils_1.default.mkdir(path_1.default.dirname(outPath));
                    fs_1.default.copyFileSync(path_1.default.join(bundleDir, value.path), outPath);
                });
                const zipOutFile = path_1.default.join(outputDir, `${key}_${versionItem}_${newVersion}.zip`);
                const fileCount = FileUtils_1.default.fileCount(zipCacheDir, true);
                yield FileUtils_1.default.zipdir(zipCacheDir, zipOutFile);
                FileUtils_1.default.rm(zipCacheDir);
                const zipStat = fs_1.default.statSync(zipOutFile);
                const zipMD5 = MD5Utils_1.default.md5Dir(zipOutFile)[0].md5;
                packages.push({ version: versionItem, size: zipStat.size, files: fileCount, md5: zipMD5 });
            }
            FileUtils_1.default.rm(zipCacheOutputDir);
            const zipOutFile = path_1.default.join(outputDir, `${key}_${newVersion}.zip`);
            const fileCount = FileUtils_1.default.fileCount(bundleDir, true);
            yield FileUtils_1.default.zipdir(bundleDir, zipOutFile);
            const zipStat = fs_1.default.statSync(zipOutFile);
            const zipMD5 = MD5Utils_1.default.md5Dir(zipOutFile)[0].md5;
            packages.push({ version: 0, size: zipStat.size, files: fileCount, md5: zipMD5 });
            writePackageRecord(newVersion, { md5 }, versionCacheDir);
            const mainConfig = mainConfigs.find(value => value.key === key);
            if (mainConfig) {
                mainConfig.version = newVersion;
                mainConfig.supports = existVersions;
            }
            else {
                mainConfigs.push({ key, version: newVersion, supports: existVersions });
            }
            writeMainConfig(url, mainConfigs);
            config.version = newVersion;
            config.packages = packages;
            writePackageConfig(url, key, config);
            packageResult.packageVersion = newVersion;
            packageResult.size = zipStat.size;
            console.log(`Package [${key}] build finished`);
        }
        else if (md5Compare.deleted.length) {
            console.log(`Package [${key}] no changes (but delete)`);
        }
        else {
            console.log(`Package [${key}] no changes`);
        }
        console.log(`save package [${key}] config`);
        const configFileName = `subgame_config_${key}_${frameworkVersion}.json`;
        const configFilePath = path_1.default.join(outputDir, configFileName);
        fs_1.default.writeFileSync(configFilePath, JSON.stringify(config));
        console.log(`save main config`);
        fs_1.default.writeFileSync(path_1.default.join(outputDir, `subgame_config_${frameworkVersion}.json`), JSON.stringify(mainConfigs));
        FileUtils_1.default.rm(bundleDir);
        console.log(`Package [${key}] build result: \n ${JSON.stringify(packageResult)}`);
        console.log(`-----------------------------------------------------Handle package [${key}] end-------------------------------------------------------\n\n`);
        return packageResult;
    });
}
exports.default = PackageAndroid;
