import sharp from "sharp";
import { writeFileSync, readFileSync } from "node:fs";
import { resolve } from "node:path";

const ROOT = resolve(import.meta.dirname, "..");
const SOURCE = resolve(ROOT, "public/image/Studio/Logo Flat.png");
const OUT_ICON_PNG = resolve(ROOT, "app/icon.png");
const OUT_FAVICON_ICO = resolve(ROOT, "app/favicon.ico");
const OUT_PUBLIC_PNG = resolve(ROOT, "public/image/Studio/favicon.png");

const SIZE = 512;
const MOUNTAIN_FILL = 0.78;

async function makeFavicon(size) {
  const circle = Buffer.from(
    `<svg xmlns="http://www.w3.org/2000/svg" width="${size}" height="${size}">
      <circle cx="${size / 2}" cy="${size / 2}" r="${size / 2}" fill="#000000"/>
    </svg>`
  );

  const mountainTargetW = Math.round(size * MOUNTAIN_FILL);
  const mountain = await sharp(SOURCE)
    .resize({ width: mountainTargetW })
    .toBuffer();
  const mountainMeta = await sharp(mountain).metadata();

  return sharp(circle)
    .composite([
      {
        input: mountain,
        top: Math.round((size - mountainMeta.height) / 2) + Math.round(size * 0.03),
        left: Math.round((size - mountainMeta.width) / 2),
      },
    ])
    .png()
    .toBuffer();
}

function buildIco(pngBuffers) {
  const count = pngBuffers.length;
  const header = Buffer.alloc(6);
  header.writeUInt16LE(0, 0);
  header.writeUInt16LE(1, 2);
  header.writeUInt16LE(count, 4);

  const dirEntries = [];
  let offset = 6 + count * 16;
  for (const { buffer, size } of pngBuffers) {
    const entry = Buffer.alloc(16);
    entry.writeUInt8(size === 256 ? 0 : size, 0);
    entry.writeUInt8(size === 256 ? 0 : size, 1);
    entry.writeUInt8(0, 2);
    entry.writeUInt8(0, 3);
    entry.writeUInt16LE(1, 4);
    entry.writeUInt16LE(32, 6);
    entry.writeUInt32LE(buffer.length, 8);
    entry.writeUInt32LE(offset, 12);
    dirEntries.push(entry);
    offset += buffer.length;
  }

  return Buffer.concat([header, ...dirEntries, ...pngBuffers.map((p) => p.buffer)]);
}

const big = await makeFavicon(SIZE);
writeFileSync(OUT_ICON_PNG, big);
writeFileSync(OUT_PUBLIC_PNG, big);

const icoSizes = [16, 32, 48];
const icoPngs = await Promise.all(
  icoSizes.map(async (s) => ({
    size: s,
    buffer: await sharp(big).resize(s, s).png({ compressionLevel: 9 }).toBuffer(),
  }))
);
writeFileSync(OUT_FAVICON_ICO, buildIco(icoPngs));

console.log("icon.png:", big.length, "bytes");
console.log("favicon.ico:", readFileSync(OUT_FAVICON_ICO).length, "bytes");
