"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.BuildService = void 0;
const child_process_1 = require("child_process");
const path_1 = __importDefault(require("path"));
const fs_1 = __importDefault(require("fs"));
const archiver_1 = __importDefault(require("archiver"));
const configGenerator_1 = require("./configGenerator");
const storageService_1 = require("./storageService");
const TEMPLATE_DIR = path_1.default.resolve(__dirname, "../../../../templates/coloring");
const BUILD_TIMEOUT_MS = 120_000; // 单次构建超时 120s
class BuildService {
    db;
    storageDir;
    queue = [];
    running = false;
    constructor(db, storageDir) {
        this.db = db;
        this.storageDir = storageDir;
    }
    enqueue(buildId, creativeId, platforms, theme) {
        this.queue.push(() => this.build(buildId, creativeId, platforms, theme));
        if (!this.running) {
            this.processQueue();
        }
    }
    async processQueue() {
        this.running = true;
        while (this.queue.length > 0) {
            const task = this.queue.shift();
            try {
                await task();
            }
            catch (err) {
                console.error("[build] Queue task failed:", err);
            }
        }
        this.running = false;
    }
    async build(buildId, creativeId, platforms, theme) {
        const startTime = new Date().toISOString();
        try {
            // 更新状态 → building
            this.db
                .prepare("UPDATE builds SET status = 'building', started_at = ? WHERE id = ?")
                .run(startTime, buildId);
            // 1. 创建 symlink
            (0, configGenerator_1.createAssetsSymlink)(creativeId, this.storageDir);
            // 2. 生成 _ad_config_.ts
            const configContent = (0, configGenerator_1.generateAdConfig)({
                creativeId,
                theme,
                storageDir: this.storageDir,
            });
            const configPath = path_1.default.join(TEMPLATE_DIR, "src", "filler", "_ad_config_.ts");
            fs_1.default.writeFileSync(configPath, configContent, "utf-8");
            console.log(`[build] Generated _ad_config_.ts for creative ${creativeId}`);
            // 3. 构建输出目录
            const buildOutputDir = path_1.default.join(this.storageDir, "creatives", creativeId, "builds", buildId);
            (0, storageService_1.ensureDir)(buildOutputDir);
            // 4. 逐平台构建
            const results = [];
            for (const platform of platforms) {
                console.log(`[build] Building ${platform} for creative ${creativeId}...`);
                await this.runViteBuild(platform);
                await this.collectOutput(buildOutputDir, platform, results);
            }
            // 5. 复制预览产物（用第一个平台的输出即可，供真机扫码测试）
            const previewSrc = path_1.default.join(TEMPLATE_DIR, "dist", platforms[0], "index.html");
            const previewDir = path_1.default.join(this.storageDir, "previews");
            (0, storageService_1.ensureDir)(previewDir);
            const previewId = buildId.replace(/-/g, "").slice(0, 8);
            const previewPath = path_1.default.join(previewDir, `${previewId}.html`);
            fs_1.default.copyFileSync(previewSrc, previewPath);
            console.log(`[build] Preview file: ${previewPath} (from ${platforms[0]})`);
            // 7. 打包 ZIP
            await this.createZip(buildOutputDir, results);
            // 6. 更新数据库
            const finishedAt = new Date().toISOString();
            this.db
                .prepare(`UPDATE builds SET status = 'completed', results = ?, finished_at = ? WHERE id = ?`)
                .run(JSON.stringify(results), finishedAt, buildId);
            // 更新创意状态
            this.db
                .prepare("UPDATE creatives SET status = 'built', updated_at = datetime('now') WHERE id = ?")
                .run(creativeId);
            console.log(`[build] Build ${buildId} completed: ${results.map((r) => r.platform).join(", ")}`);
        }
        catch (err) {
            console.error(`[build] Build ${buildId} failed:`, err.message);
            this.db
                .prepare("UPDATE builds SET status = 'failed', error_log = ? WHERE id = ?")
                .run(err.message || "Unknown error", buildId);
            this.db
                .prepare("UPDATE creatives SET status = 'assets_ready', updated_at = datetime('now') WHERE id = ?")
                .run(creativeId);
        }
        finally {
            // 清理临时文件
            (0, configGenerator_1.cleanupBuildArtifacts)();
        }
    }
    runViteBuild(platform) {
        return new Promise((resolve, reject) => {
            const cmd = `cd ${TEMPLATE_DIR} && AD_CONFIG_PATH=src/filler/_ad_config_.ts npx vite build --mode ${platform}`;
            console.log(`[build] Executing: ${cmd}`);
            (0, child_process_1.exec)(cmd, { timeout: BUILD_TIMEOUT_MS }, (error, stdout, stderr) => {
                if (stdout)
                    console.log(`[vite:${platform}]`, stdout.slice(-500));
                if (stderr && !stderr.includes("vite"))
                    console.error(`[vite:${platform}]`, stderr.slice(-500));
                if (error) {
                    reject(new Error(`Vite build failed for ${platform}: ${error.message}`));
                }
                else {
                    resolve();
                }
            });
        });
    }
    async collectOutput(buildOutputDir, platform, results) {
        const distPath = path_1.default.join(TEMPLATE_DIR, "dist", platform, "index.html");
        const destDir = path_1.default.join(buildOutputDir, platform);
        (0, storageService_1.ensureDir)(destDir);
        const destPath = path_1.default.join(destDir, "index.html");
        if (!fs_1.default.existsSync(distPath)) {
            throw new Error(`Build output not found for platform ${platform}: ${distPath}`);
        }
        fs_1.default.copyFileSync(distPath, destPath);
        const stat = fs_1.default.statSync(destPath);
        results.push({ platform, fileSize: stat.size });
    }
    createZip(buildOutputDir, results) {
        return new Promise((resolve, reject) => {
            const zipPath = path_1.default.join(buildOutputDir, "all.zip");
            const output = fs_1.default.createWriteStream(zipPath);
            const archive = (0, archiver_1.default)("zip", { zlib: { level: 9 } });
            output.on("close", resolve);
            archive.on("error", reject);
            archive.pipe(output);
            for (const r of results) {
                const filePath = path_1.default.join(buildOutputDir, r.platform, "index.html");
                if (fs_1.default.existsSync(filePath)) {
                    archive.file(filePath, { name: `${r.platform}/index.html` });
                }
            }
            archive.finalize();
        });
    }
}
exports.BuildService = BuildService;
//# sourceMappingURL=buildService.js.map