/**
 * Generates 81×81 RGBA PNG tab bar icons (no npm deps — zlib + raw PNG).
 * Run: node tools/generate-tabbar-icons.js
 */

import { createWriteStream, mkdirSync } from "fs";
import { dirname, join } from "path";
import { fileURLToPath } from "url";
import { deflateSync } from "zlib";

const __dirname = dirname(fileURLToPath(import.meta.url));

const W = 81;
const H = 81;

const OUT_DIR = join(__dirname, "../miniprogram/assets/tabBar");

const PNG_SIG = Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]);

/** PNG CRC-32 (polynomial 0xedb88320) */
function crc32(buf) {
  let c = 0xffffffff;
  for (let i = 0; i < buf.length; i++) {
    c ^= buf[i];
    for (let k = 0; k < 8; k++) {
      c = (c >>> 1) ^ (0xedb88320 & -(c & 1));
    }
  }
  return (c ^ 0xffffffff) >>> 0;
}

function chunk(type, data) {
  const t = Buffer.from(type, "ascii");
  const len = Buffer.allocUnsafe(4);
  len.writeUInt32BE(data.length, 0);
  const crc = Buffer.allocUnsafe(4);
  crc.writeUInt32BE(crc32(Buffer.concat([t, data])), 0);
  return Buffer.concat([len, t, data, crc]);
}

function encodePng(rgba) {
  const rowLen = 1 + W * 4;
  const raw = Buffer.allocUnsafe(H * rowLen);
  let o = 0;
  for (let y = 0; y < H; y++) {
    raw[o++] = 0; // filter: None
    const rowStart = y * W * 4; // top row first (y = 0)
    rgba.copy(raw, o, rowStart, rowStart + W * 4);
    o += W * 4;
  }

  const ihdr = Buffer.allocUnsafe(13);
  ihdr.writeUInt32BE(W, 0);
  ihdr.writeUInt32BE(H, 4);
  ihdr[8] = 8; // bit depth
  ihdr[9] = 6; // RGBA
  ihdr[10] = 0;
  ihdr[11] = 0;
  ihdr[12] = 0;

  const idat = deflateSync(raw, { level: 9 });
  return Buffer.concat([PNG_SIG, chunk("IHDR", ihdr), chunk("IDAT", idat), chunk("IEND", Buffer.alloc(0))]);
}

function parseHexRgb(hex) {
  const h = hex.replace("#", "");
  return {
    r: parseInt(h.slice(0, 2), 16),
    g: parseInt(h.slice(2, 4), 16),
    b: parseInt(h.slice(4, 6), 16),
  };
}

function setPixel(rgba, x, y, r, g, b, a) {
  if (x < 0 || x >= W || y < 0 || y >= H) return;
  const i = (y * W + x) * 4;
  rgba[i] = r;
  rgba[i + 1] = g;
  rgba[i + 2] = b;
  rgba[i + 3] = a;
}

function fillTriangle(rgba, x0, y0, x1, y1, x2, y2, r, g, b, a) {
  const ymin = Math.max(0, Math.min(y0, y1, y2));
  const ymax = Math.min(H - 1, Math.max(y0, y1, y2));
  for (let y = ymin; y <= ymax; y++) {
    const xs = [];
    const edge = (xa, ya, xb, yb) => {
      if (ya === yb) {
        if (y === ya) {
          const lo = Math.min(xa, xb);
          const hi = Math.max(xa, xb);
          xs.push(lo, hi);
        }
        return;
      }
      if (y < Math.min(ya, yb) || y > Math.max(ya, yb)) return;
      const t = (y - ya) / (yb - ya);
      xs.push(Math.round(xa + t * (xb - xa)));
    };
    edge(x0, y0, x1, y1);
    edge(x1, y1, x2, y2);
    edge(x2, y2, x0, y0);
    if (xs.length < 2) continue;
    const xMin = Math.max(0, Math.min(...xs));
    const xMax = Math.min(W - 1, Math.max(...xs));
    for (let x = xMin; x <= xMax; x++) setPixel(rgba, x, y, r, g, b, a);
  }
}

function fillRect(rgba, x0, y0, x1, y1, r, g, b, a) {
  const xa = Math.max(0, Math.min(x0, x1));
  const xb = Math.min(W - 1, Math.max(x0, x1));
  const ya = Math.max(0, Math.min(y0, y1));
  const yb = Math.min(H - 1, Math.max(y0, y1));
  for (let y = ya; y <= yb; y++) {
    for (let x = xa; x <= xb; x++) setPixel(rgba, x, y, r, g, b, a);
  }
}

function fillCircle(rgba, cx, cy, rad, r, g, b, a) {
  const r2 = rad * rad;
  const x0 = Math.max(0, Math.floor(cx - rad - 1));
  const x1 = Math.min(W - 1, Math.ceil(cx + rad + 1));
  const y0 = Math.max(0, Math.floor(cy - rad - 1));
  const y1 = Math.min(H - 1, Math.ceil(cy + rad + 1));
  for (let y = y0; y <= y1; y++) {
    for (let x = x0; x <= x1; x++) {
      const dx = x - cx;
      const dy = y - cy;
      if (dx * dx + dy * dy <= r2) setPixel(rgba, x, y, r, g, b, a);
    }
  }
}

function fillEllipse(rgba, cx, cy, rx, ry, r, g, b, a, yMin = 0, yMax = H - 1) {
  const x0 = Math.max(0, Math.floor(cx - rx - 1));
  const x1 = Math.min(W - 1, Math.ceil(cx + rx + 1));
  const ya = Math.max(0, yMin);
  const yb = Math.min(H - 1, yMax);
  const rx2 = rx * rx;
  const ry2 = ry * ry;
  for (let y = ya; y <= yb; y++) {
    for (let x = x0; x <= x1; x++) {
      const dx = x - cx;
      const dy = y - cy;
      if (dx * dx * ry2 + dy * dy * rx2 <= rx2 * ry2) setPixel(rgba, x, y, r, g, b, a);
    }
  }
}

function drawHome(rgba, rgb) {
  const { r, g, b } = rgb;
  const a = 255;
  // Roof: triangle
  fillTriangle(rgba, 40, 15, 20, 34, 60, 34, r, g, b, a);
  // Body
  fillRect(rgba, 26, 34, 54, 56, r, g, b, a);
}

function drawAge(rgba, rgb) {
  const { r, g, b } = rgb;
  const a = 255;
  fillCircle(rgba, 40, 24, 10, r, g, b, a);
  fillRect(rgba, 32, 35, 48, 59, r, g, b, a);
}

function drawHeart(rgba, rgb) {
  const { r, g, b } = rgb;
  const a = 255;
  const cx = 40;
  const cy = 38;
  const s = 19;
  for (let py = 0; py < H; py++) {
    for (let px = 0; px < W; px++) {
      const x = (px - cx) / s;
      const y = -(py - cy) / s;
      const x2 = x * x;
      const y2 = y * y;
      const t = x2 + y2 - 1;
      if (t * t * t - x2 * y * y * y <= 0) setPixel(rgba, px, py, r, g, b, a);
    }
  }
}

function drawProfile(rgba, rgb) {
  const { r, g, b } = rgb;
  const a = 255;
  fillCircle(rgba, 40, 25, 10, r, g, b, a);
  // Wider shoulder ellipse (lower half reads as arc)
  fillEllipse(rgba, 40, 52, 27, 13, r, g, b, a, 38, H - 1);
}

function writePng(path, png) {
  mkdirSync(dirname(path), { recursive: true });
  return new Promise((resolve, reject) => {
    const ws = createWriteStream(path);
    ws.on("error", reject);
    ws.on("finish", resolve);
    ws.end(png);
  });
}

const COLOR_NORMAL = parseHexRgb("#999999");
const COLOR_ACTIVE = parseHexRgb("#333333");

const jobs = [
  { name: "icon-home.png", draw: drawHome, color: COLOR_NORMAL },
  { name: "icon-home-active.png", draw: drawHome, color: COLOR_ACTIVE },
  { name: "icon-age.png", draw: drawAge, color: COLOR_NORMAL },
  { name: "icon-age-active.png", draw: drawAge, color: COLOR_ACTIVE },
  { name: "icon-fav.png", draw: drawHeart, color: COLOR_NORMAL },
  { name: "icon-fav-active.png", draw: drawHeart, color: COLOR_ACTIVE },
  { name: "icon-profile.png", draw: drawProfile, color: COLOR_NORMAL },
  { name: "icon-profile-active.png", draw: drawProfile, color: COLOR_ACTIVE },
];

async function main() {
  for (const { name, draw, color } of jobs) {
    const rgba = Buffer.alloc(W * H * 4, 0);
    draw(rgba, color);
    const png = encodePng(rgba);
    const out = join(OUT_DIR, name);
    await writePng(out, png);
    console.log("Wrote", out, `(${png.length} bytes)`);
  }
}

main().catch((e) => {
  console.error(e);
  process.exit(1);
});
