#!/usr/bin/env bun
/**
 * 图标构建:把 `ui/icon.svg` 渲染成多尺寸 Windows 图标 `src-tauri/icons/icon.ico`,
 * 同时输出预览 PNG 到 `.verify/icon/icon-256.png` 供人工与视觉模型核对。
 *
 * 渲染走本机 Edge/Chrome(复用执行器的 spawn + CDP 逻辑),全程离线、不需要额外依赖。
 * 用法:bun run scripts/make-icon.ts
 */
import path from "node:path";
import { mkdir, readFile, writeFile } from "node:fs/promises";
import { loadConfig } from "../src/config.ts";
import { withBrowser } from "../src/runner/driver.ts";

/** ICO 里包含的尺寸(16/32 供任务栏与资源管理器,256 供大图标视图)。 */
const SIZES = [16, 24, 32, 48, 64, 128, 256] as const;

const root = path.resolve(import.meta.dir, "..");
const svgPath = path.join(root, "ui", "icon.svg");
const icoPath = path.join(root, "src-tauri", "icons", "icon.ico");
const previewPath = path.join(root, ".verify", "icon", "icon-256.png");

interface Frame {
  size: number;
  png: Uint8Array;
}

/** 组装 ICO:6 字节文件头 + 每帧 16 字节目录项 + PNG 负载(Vista 起支持 PNG 帧)。 */
function buildIco(frames: Frame[]): Uint8Array {
  const header = Buffer.alloc(6);
  header.writeUInt16LE(0, 0); // reserved
  header.writeUInt16LE(1, 2); // type: icon
  header.writeUInt16LE(frames.length, 4);

  const directory = Buffer.alloc(frames.length * 16);
  let offset = header.length + directory.length;
  frames.forEach((frame, index) => {
    const entry = index * 16;
    directory.writeUInt8(frame.size >= 256 ? 0 : frame.size, entry + 0);
    directory.writeUInt8(frame.size >= 256 ? 0 : frame.size, entry + 1);
    directory.writeUInt8(0, entry + 2); // 调色板色数(真彩为 0)
    directory.writeUInt8(0, entry + 3); // reserved
    directory.writeUInt16LE(1, entry + 4); // color planes
    directory.writeUInt16LE(32, entry + 6); // bits per pixel
    directory.writeUInt32LE(frame.png.length, entry + 8);
    directory.writeUInt32LE(offset, entry + 12);
    offset += frame.png.length;
  });

  return Buffer.concat([header, directory, ...frames.map((frame) => Buffer.from(frame.png))]);
}

const svg = await readFile(svgPath, "utf8");
const cfg = await loadConfig({ cwd: root });

const frames = await withBrowser(cfg.runner, async (page, context) => {
  // CDP 连接的页面不支持 page.setViewportSize,改用 CDP 的设备指标与透明底色覆盖
  const session = await context.newCDPSession(page);
  await session.send("Emulation.setDefaultBackgroundColorOverride", { color: { r: 0, g: 0, b: 0, a: 0 } });
  const collected: Frame[] = [];
  for (const size of SIZES) {
    await session.send("Emulation.setDeviceMetricsOverride", {
      width: size,
      height: size,
      deviceScaleFactor: 1,
      mobile: false,
    });
    await page.setContent(
      `<!doctype html><html><head><meta charset="utf-8"><style>
         html,body{margin:0;padding:0;background:transparent;width:${size}px;height:${size}px;overflow:hidden}
         svg{display:block;width:${size}px;height:${size}px}
       </style></head><body>${svg.replace(/width="512" height="512"/, `width="${size}" height="${size}"`)}</body></html>`,
    );
    await page.waitForTimeout(150);
    const png = await page.screenshot({
      omitBackground: true,
      type: "png",
      clip: { x: 0, y: 0, width: size, height: size },
    });
    collected.push({ size, png: new Uint8Array(png) });
  }
  return collected;
});

const ico = buildIco(frames);
await mkdir(path.dirname(icoPath), { recursive: true });
await writeFile(icoPath, ico);
await mkdir(path.dirname(previewPath), { recursive: true });
const preview = frames.find((frame) => frame.size === 256);
if (preview) await writeFile(previewPath, preview.png);

console.log(`已生成 ${path.relative(root, icoPath)}(${frames.length} 帧:${SIZES.join("/")},${ico.length} 字节)`);
console.log(`预览图:${path.relative(root, previewPath)}`);