/**
 * Compare Figma light exports against existing ui-kit pictos using perceptual hash.
 * Used to validate the picto-figma-map.json name mappings.
 *
 * Usage:
 *   bun tools/picto-compare.ts <urls-manifest.json>
 *
 * Manifest format: [{ fileName: "PadlockClosed", nodeId, url }] for light versions
 */

import { execSync } from "node:child_process";
import { mkdir, readFile, writeFile } from "node:fs/promises";
import { join } from "node:path";

const PICTOS_DIR = join(import.meta.dir, "../src/assets/pictos");
const TMP = join(import.meta.dir, "../.picto-compare");

async function phash(path: string): Promise<string> {
    return execSync(`magick "${path}" -colorspace Gray -resize 16x16! -depth 8 txt:-`, {
        encoding: "utf8",
    });
}

function hashDistance(a: string, b: string): number {
    const valsA = [...a.matchAll(/\\((\\d+),(\\d+)\\)\\s+#(\\w+)/g)].map((m) =>
        Number.parseInt(m[3], 16),
    );
    const valsB = [...b.matchAll(/\\((\\d+),(\\d+)\\)\\s+#(\\w+)/g)].map((m) =>
        Number.parseInt(m[3], 16),
    );
    let dist = 0;
    for (let i = 0; i < Math.min(valsA.length, valsB.length); i++) {
        dist += Math.abs(valsA[i] - valsB[i]);
    }
    return dist;
}

async function main() {
    const manifest: { fileName: string; url: string }[] = JSON.parse(
        await readFile(process.argv[2], "utf8"),
    );
    await mkdir(TMP, { recursive: true });

    const results: { fileName: string; distance: number; matched: boolean }[] = [];

    for (const { fileName, url } of manifest) {
        const figmaPng = join(TMP, `${fileName}-figma.png`);
        const res = await fetch(url);
        await writeFile(figmaPng, await res.arrayBuffer());

        const repoWebp = join(PICTOS_DIR, `${fileName}.webp`);
        const repoPng = join(TMP, `${fileName}-repo.png`);
        execSync(`magick "${repoWebp}" "${repoPng}"`);

        const dist = hashDistance(await phash(figmaPng), await phash(repoPng));
        results.push({ fileName, distance: dist, matched: dist < 5000 });
    }

    const failed = results.filter((r) => !r.matched);
    console.log(`Compared ${results.length}, mismatches: ${failed.length}`);
    for (const f of failed) console.log(`  ${f.fileName}: distance ${f.distance}`);
}

main().catch(console.error);
