"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.assetsRouter = assetsRouter;
const express_1 = require("express");
const multer_1 = __importDefault(require("multer"));
const adm_zip_1 = __importDefault(require("adm-zip"));
const path_1 = __importDefault(require("path"));
const fs_1 = __importDefault(require("fs"));
const storageService_1 = require("../services/storageService");
const upload = (0, multer_1.default)({
    storage: multer_1.default.memoryStorage(),
    limits: { fileSize: 50 * 1024 * 1024 },
    fileFilter: (_req, file, cb) => {
        if (file.mimetype === "application/zip" ||
            file.mimetype === "application/x-zip-compressed" ||
            file.originalname.endsWith(".zip")) {
            cb(null, true);
        }
        else {
            cb(new Error("Only .zip files are allowed"));
        }
    },
});
/**
 * 从 zip buffer 中提取素材文件、校验、写入磁盘、更新 DB。
 * 文件上传和 URL 导入共用此逻辑。
 */
function extractAndSave(zipBuffer, manifest, assetsDir, db, creativeId) {
    const requiredAssets = manifest.assets?.required ?? [];
    const optionalAssets = manifest.assets?.optional ?? [];
    const allAssetDefs = [...requiredAssets, ...optionalAssets];
    // 清理并重建素材目录
    if (fs_1.default.existsSync(assetsDir)) {
        fs_1.default.rmSync(assetsDir, { recursive: true, force: true });
    }
    fs_1.default.mkdirSync(assetsDir, { recursive: true });
    const zip = new adm_zip_1.default(zipBuffer);
    const zipEntries = zip.getEntries();
    const extractedFiles = [];
    const warnings = [];
    // 清空旧素材记录
    db.prepare("DELETE FROM creative_assets WHERE creative_id = ?").run(creativeId);
    // 匹配并解压文件
    for (const def of allAssetDefs) {
        const entry = zipEntries.find((e) => {
            const entryName = path_1.default.basename(e.entryName).toLowerCase();
            const expectedName = def.file.toLowerCase();
            return entryName === expectedName;
        });
        if (entry) {
            const fileName = def.file;
            const filePath = path_1.default.join(assetsDir, fileName);
            fs_1.default.writeFileSync(filePath, entry.getData());
            const stat = fs_1.default.statSync(filePath);
            const isRequired = requiredAssets.some((r) => r.key === def.key);
            db.prepare("INSERT INTO creative_assets (creative_id, file_key, file_name, file_path, file_size, is_required) VALUES (?, ?, ?, ?, ?, ?)").run(creativeId, def.key, fileName, filePath, stat.size, isRequired ? 1 : 0);
            extractedFiles.push({ key: def.key, fileName, fileSize: stat.size, valid: true });
        }
        else if (requiredAssets.some((r) => r.key === def.key)) {
            warnings.push(`Required file '${def.file}' is missing from uploaded zip`);
            extractedFiles.push({ key: def.key, fileName: def.file, fileSize: 0, valid: false });
        }
    }
    // 检查未知文件
    for (const entry of zipEntries) {
        if (entry.isDirectory)
            continue;
        const entryName = path_1.default.basename(entry.entryName).toLowerCase();
        const known = allAssetDefs.some((d) => d.file.toLowerCase() === entryName);
        if (!known) {
            warnings.push(`Unknown file '${entry.entryName}' ignored`);
        }
    }
    return { files: extractedFiles, warnings };
}
function assetsRouter(db, storageDir) {
    const router = (0, express_1.Router)();
    // POST /api/v1/creatives/:id/assets/upload
    // 支持两种方式：
    //   - multipart/form-data 上传 .zip 文件（file 字段）
    //   - application/json 提供素材 URL（{ url: "https://..." }）
    router.post("/creatives/:id/assets/upload", upload.single("file"), async (req, res) => {
        try {
            const creativeId = req.params.id;
            // 校验创意存在
            const creative = db
                .prepare("SELECT c.*, t.manifest FROM creatives c JOIN templates t ON c.template_id = t.id WHERE c.id = ?")
                .get(creativeId);
            if (!creative) {
                res.status(404).json({ error: { message: "Creative not found" } });
                return;
            }
            const manifest = JSON.parse(creative.manifest);
            const assetsDir = path_1.default.join(storageDir, "creatives", creativeId, "assets");
            let zipBuffer = null;
            // 方式 1：文件上传
            if (req.file) {
                zipBuffer = req.file.buffer;
            }
            // 方式 2：URL 导入
            else if (req.body?.url) {
                const parsed = (0, storageService_1.parseDetailUrl)(req.body.url);
                if (!parsed) {
                    res.status(400).json({
                        error: { message: "无法解析素材 URL，请确认格式正确" },
                    });
                    return;
                }
                console.log(`[assets] Downloading encrypted zip: ${parsed.zipUrl}`);
                const encrypted = await (0, storageService_1.downloadFile)(parsed.zipUrl);
                console.log(`[assets] Decrypting with key: ${parsed.id}`);
                zipBuffer = (0, storageService_1.xorDecryptBuffer)(encrypted, parsed.id);
            }
            else {
                res.status(400).json({
                    error: { message: "请上传素材 zip 文件或提供素材 URL" },
                });
                return;
            }
            // 共用解压 & 校验逻辑
            const { files, warnings } = extractAndSave(zipBuffer, manifest, assetsDir, db, creativeId);
            // 更新创意状态
            const missingRequired = files.some((f) => !f.valid);
            db.prepare("UPDATE creatives SET status = ?, updated_at = datetime('now') WHERE id = ?").run(missingRequired ? "draft" : "assets_ready", creativeId);
            res.json({ data: { files, warnings } });
        }
        catch (err) {
            console.error("[assets] Upload error:", err.message);
            res.status(500).json({ error: { message: err.message } });
        }
    });
    // GET /api/v1/creatives/:id/assets/:key — 获取单个素材文件（用于缩略图展示）
    router.get("/creatives/:id/assets/:key", (req, res) => {
        const creativeId = req.params.id;
        const fileKey = req.params.key;
        const asset = db
            .prepare("SELECT file_path, file_name FROM creative_assets WHERE creative_id = ? AND file_key = ?")
            .get(creativeId, fileKey);
        if (!asset) {
            res.status(404).json({ error: { message: "Asset not found" } });
            return;
        }
        if (!fs_1.default.existsSync(asset.file_path)) {
            res.status(404).json({ error: { message: "File not found on disk" } });
            return;
        }
        const ext = path_1.default.extname(asset.file_name).toLowerCase();
        const mimeTypes = {
            ".png": "image/png",
            ".jpg": "image/jpeg",
            ".jpeg": "image/jpeg",
            ".gif": "image/gif",
            ".webp": "image/webp",
            ".svg": "image/svg+xml",
        };
        const contentType = mimeTypes[ext] || "application/octet-stream";
        res.setHeader("Content-Type", contentType);
        res.setHeader("Cache-Control", "public, max-age=3600");
        fs_1.default.createReadStream(asset.file_path).pipe(res);
    });
    // DELETE /api/v1/creatives/:id/assets — 清除素材
    router.delete("/creatives/:id/assets", (req, res) => {
        const creativeId = req.params.id;
        const assetsDir = path_1.default.join(storageDir, "creatives", creativeId, "assets");
        if (fs_1.default.existsSync(assetsDir)) {
            fs_1.default.rmSync(assetsDir, { recursive: true, force: true });
        }
        db.prepare("DELETE FROM creative_assets WHERE creative_id = ?").run(creativeId);
        db.prepare("UPDATE creatives SET status = 'draft', updated_at = datetime('now') WHERE id = ?").run(creativeId);
        res.json({ data: { id: creativeId, cleared: true } });
    });
    return router;
}
//# sourceMappingURL=assets.js.map