import { Router } from "express";
import Database from "better-sqlite3";
import multer from "multer";
import AdmZip from "adm-zip";
import path from "path";
import fs from "fs";
import {
  parseDetailUrl,
  downloadFile,
  xorDecryptBuffer,
} from "../services/storageService";

const upload = multer({
  storage: multer.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"));
    }
  },
});

// 单图片上传（logo/slogon 等手动替换）
const uploadImage = multer({
  storage: multer.memoryStorage(),
  limits: { fileSize: 5 * 1024 * 1024 },
  fileFilter: (_req, file, cb) => {
    if (file.mimetype.startsWith("image/")) {
      cb(null, true);
    } else {
      cb(new Error("Only image files are allowed"));
    }
  },
});

/**
 * 从 zip buffer 中提取素材文件、校验、写入磁盘、更新 DB。
 * 文件上传和 URL 导入共用此逻辑。
 */
function extractAndSave(
  zipBuffer: Buffer,
  manifest: any,
  assetsDir: string,
  db: Database.Database,
  creativeId: string
): { files: Array<{ key: string; fileName: string; fileSize: number; valid: boolean }>; warnings: string[] } {
  const requiredAssets: Array<{ key: string; file: string }> = manifest.assets?.required ?? [];
  const optionalAssets: Array<{ key: string; file: string }> = manifest.assets?.optional ?? [];
  const allAssetDefs = [...requiredAssets, ...optionalAssets];

  // 清理并重建素材目录
  if (fs.existsSync(assetsDir)) {
    fs.rmSync(assetsDir, { recursive: true, force: true });
  }
  fs.mkdirSync(assetsDir, { recursive: true });

  const zip = new AdmZip(zipBuffer);
  const zipEntries = zip.getEntries();
  const extractedFiles: Array<{
    key: string;
    fileName: string;
    fileSize: number;
    valid: boolean;
  }> = [];
  const warnings: string[] = [];

  // 清空旧素材记录
  db.prepare("DELETE FROM creative_assets WHERE creative_id = ?").run(creativeId);

  // 匹配并解压文件
  for (const def of allAssetDefs) {
    const entry = zipEntries.find((e) => {
      const entryName = path.basename(e.entryName).toLowerCase();
      const expectedName = def.file.toLowerCase();
      return entryName === expectedName;
    });

    if (entry) {
      const fileName = def.file;
      const filePath = path.join(assetsDir, fileName);
      fs.writeFileSync(filePath, entry.getData());

      const stat = fs.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.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 };
}

export function assetsRouter(db: Database.Database, storageDir: string): Router {
  const router = 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 as string;

      // 校验创意存在
      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) as any;

      if (!creative) {
        res.status(404).json({ error: { message: "Creative not found" } });
        return;
      }

      const manifest = JSON.parse(creative.manifest);
      const assetsDir = path.join(storageDir, "creatives", creativeId, "assets");

      let zipBuffer: Buffer | null = null;

      // 方式 1：文件上传
      if (req.file) {
        zipBuffer = req.file.buffer;
      }
      // 方式 2：URL 导入
      else if (req.body?.url) {
        const parsed = 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 downloadFile(parsed.zipUrl);

        console.log(`[assets] Decrypting with key: ${parsed.id}`);
        zipBuffer = 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: any) {
      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 as string;
    const fileKey = req.params.key as string;

    // 1. 先查用户上传的素材
    const asset = db
      .prepare("SELECT file_path, file_name FROM creative_assets WHERE creative_id = ? AND file_key = ?")
      .get(creativeId, fileKey) as any;

    let filePath: string;
    let fileName: string;

    if (asset && fs.existsSync(asset.file_path)) {
      filePath = asset.file_path;
      fileName = asset.file_name;
    } else {
      // 2. 未上传 → 尝试回退到模板默认图
      const TEMPLATE_IMG_DIR = path.resolve(__dirname, "../../../../templates/coloring/assets/img");
      const defaultMap: Record<string, string> = {
        logo: "logo.png",
        logoTxt: "logo-txt.png",
        slogon: "slogon.png",
        coloringPages: "coloring-pages.png",
      };
      const defaultFile = defaultMap[fileKey];
      if (!defaultFile) {
        res.status(404).json({ error: { message: "Asset not found" } });
        return;
      }
      filePath = path.join(TEMPLATE_IMG_DIR, defaultFile);
      fileName = defaultFile;
      if (!fs.existsSync(filePath)) {
        res.status(404).json({ error: { message: "Default asset not found" } });
        return;
      }
    }

    const ext = path.extname(fileName).toLowerCase();
    const mimeTypes: Record<string, string> = {
      ".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.createReadStream(filePath).pipe(res);
  });

  // POST /api/v1/creatives/:id/assets/:key — 上传单个素材文件（手动替换）
  router.post("/creatives/:id/assets/:key", uploadImage.single("file"), (req, res) => {
    try {
      const creativeId = req.params.id as string;
      const fileKey = req.params.key as string;

      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) as any;
      if (!creative) { res.status(404).json({ error: { message: "Creative not found" } }); return; }

      const manifest = JSON.parse(creative.manifest);
      const requiredAssets: Array<{ key: string; file: string; accept?: string }> = manifest.assets?.required ?? [];
      const optionalAssets: Array<{ key: string; file: string; accept?: string }> = manifest.assets?.optional ?? [];
      const def = [...requiredAssets, ...optionalAssets].find((d: any) => d.key === fileKey);
      if (!def) { res.status(400).json({ error: { message: `Unknown asset key: ${fileKey}` } }); return; }

      if (!req.file) { res.status(400).json({ error: { message: "请选择文件" } }); return; }

      const assetsDir = path.join(storageDir, "creatives", creativeId, "assets");
      if (!fs.existsSync(assetsDir)) fs.mkdirSync(assetsDir, { recursive: true });

      // 删除同 key 的旧文件
      const oldAsset = db.prepare("SELECT file_path FROM creative_assets WHERE creative_id = ? AND file_key = ?").get(creativeId, fileKey) as any;
      if (oldAsset && fs.existsSync(oldAsset.file_path)) fs.unlinkSync(oldAsset.file_path);

      const filePath = path.join(assetsDir, def.file);
      fs.writeFileSync(filePath, req.file.buffer);
      const stat = fs.statSync(filePath);

      db.prepare("DELETE FROM creative_assets WHERE creative_id = ? AND file_key = ?").run(creativeId, fileKey);
      db.prepare(
        "INSERT INTO creative_assets (creative_id, file_key, file_name, file_path, file_size, is_required) VALUES (?, ?, ?, ?, ?, ?)"
      ).run(creativeId, fileKey, def.file, filePath, stat.size, requiredAssets.some((r) => r.key === fileKey) ? 1 : 0);

      console.log(`[assets] Single upload: ${fileKey} -> ${filePath} (${stat.size} bytes)`);
      res.json({ data: { key: fileKey, fileName: def.file, fileSize: stat.size, valid: true } });
    } catch (err: any) {
      console.error("[assets] Single upload error:", err.message);
      res.status(500).json({ error: { message: err.message } });
    }
  });

  // DELETE /api/v1/creatives/:id/assets — 清除素材
  router.delete("/creatives/:id/assets", (req, res) => {
    const creativeId = req.params.id as string;
    const assetsDir = path.join(storageDir, "creatives", creativeId, "assets");

    if (fs.existsSync(assetsDir)) {
      fs.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;
}
