import { existsSync, mkdirSync, rmSync } from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
import { Jimp } from "jimp";
import pngToIco from "png-to-ico";

const rootDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");

const MAC_ICONSET_ENTRIES = [
  { name: "icon_16x16.png", size: 16 },
  { name: "icon_16x16@2x.png", size: 32 },
  { name: "icon_32x32.png", size: 32 },
  { name: "icon_32x32@2x.png", size: 64 },
  { name: "icon_128x128.png", size: 128 },
  { name: "icon_128x128@2x.png", size: 256 },
  { name: "icon_256x256.png", size: 256 },
  { name: "icon_256x256@2x.png", size: 512 },
  { name: "icon_512x512.png", size: 512 },
  { name: "icon_512x512@2x.png", size: 1024 },
];

const WIN_ICO_SIZES = [16, 32, 48, 256];
const LINUX_ICON_SIZE = 256;

function resolveSourcePath(arg) {
  if (!arg) {
    return path.join(rootDir, "assets/farmcontrolhosticon.png");
  }

  const candidate = path.isAbsolute(arg) ? arg : path.resolve(rootDir, arg);
  return candidate;
}

async function resizePng(sourceImage, size) {
  return sourceImage
    .clone()
    .resize({ w: size, h: size })
    .getBuffer("image/png");
}

async function writePng(filePath, sourceImage, size) {
  const png = await resizePng(sourceImage, size);
  await Bun.write(filePath, png);
  return png;
}

function parseArgs(argv) {
  const sourceArg = argv.find((arg) => !arg.startsWith("-"));
  const outDirArgIndex = argv.indexOf("--out-dir");
  const outDir =
    outDirArgIndex >= 0 ? argv[outDirArgIndex + 1] : path.join(rootDir, "assets");

  return {
    sourcePath: resolveSourcePath(sourceArg),
    outDir: path.isAbsolute(outDir) ? outDir : path.resolve(rootDir, outDir),
  };
}

async function main() {
  const { sourcePath, outDir } = parseArgs(process.argv.slice(2));

  if (!existsSync(sourcePath)) {
    console.error(`prepare-app-icons: source image not found: ${sourcePath}`);
    process.exit(1);
  }

  const sourceImage = await Jimp.read(sourcePath);
  if (sourceImage.width < 256 || sourceImage.height < 256) {
    console.warn(
      `prepare-app-icons: source image is ${sourceImage.width}x${sourceImage.height}; Electrobun recommends at least 256x256`,
    );
  }

  mkdirSync(outDir, { recursive: true });

  const iconsetDir = path.join(outDir, "icon.iconset");
  rmSync(iconsetDir, { recursive: true, force: true });
  mkdirSync(iconsetDir, { recursive: true });

  for (const entry of MAC_ICONSET_ENTRIES) {
    const iconPath = path.join(iconsetDir, entry.name);
    await writePng(iconPath, sourceImage, entry.size);
  }

  const icoPngs = [];
  for (const size of WIN_ICO_SIZES) {
    icoPngs.push(await resizePng(sourceImage, size));
  }

  const icoPath = path.join(outDir, "icon.ico");
  await Bun.write(icoPath, await pngToIco(icoPngs));

  const linuxIconPath = path.join(outDir, "icon.png");
  await writePng(linuxIconPath, sourceImage, LINUX_ICON_SIZE);

  console.log(`prepare-app-icons: wrote ${iconsetDir}`);
  console.log(`prepare-app-icons: wrote ${icoPath}`);
  console.log(`prepare-app-icons: wrote ${linuxIconPath}`);
}

main().catch((error) => {
  console.error(`prepare-app-icons: ${error.message}`);
  process.exit(1);
});
