/**
 * Verify gradient pictos match their glass counterparts by comparing alpha silhouettes.
 * Flags pairs whose shapes diverge significantly (wrong Figma export node, etc.).
 *
 * Usage:
 *   bun tools/picto-verify-gradients.ts
 *   bun tools/picto-verify-gradients.ts --threshold 3
 */

import { execSync } from "node:child_process";
import { readdir } from "node:fs/promises";
import { join } from "node:path";

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

const fingerprintCache = new Map<string, number[]>();

function alphaFingerprint(fileName: string): number[] {
    const cached = fingerprintCache.get(fileName);
    if (cached) return cached;

    const path = join(PICTOS_DIR, fileName);
    const out = execSync(`magick "${path}" -alpha extract -resize 64x64! -threshold 10% txt:-`, {
        encoding: "utf8",
    });
    const fp = [...out.matchAll(/#([0-9A-Fa-f]+)/g)].map((m) => Number.parseInt(m[1], 16));
    fingerprintCache.set(fileName, fp);
    return fp;
}

function distance(a: number[], b: number[]): number {
    let dist = 0;
    for (let i = 0; i < Math.min(a.length, b.length); i++) {
        dist += Math.abs(a[i] - b[i]);
    }
    return dist;
}

async function main() {
    const thresholdArg = process.argv.indexOf("--threshold");
    const thresholdMultiplier =
        thresholdArg >= 0 ? Number.parseFloat(process.argv[thresholdArg + 1]) : 3;

    const glassNames = (await readdir(PICTOS_DIR))
        .filter((f) => f.endsWith(".webp") && !f.endsWith("Gradient.webp"))
        .map((f) => f.replace(/\.webp$/, ""));

    const scores: { name: string; distance: number }[] = [];

    for (const name of glassNames) {
        const gradientFile = `${name}Gradient.webp`;
        try {
            alphaFingerprint(`${name}.webp`);
            alphaFingerprint(gradientFile);
        } catch {
            continue;
        }
        scores.push({
            name,
            distance: distance(alphaFingerprint(`${name}.webp`), alphaFingerprint(gradientFile)),
        });
    }

    scores.sort((a, b) => b.distance - a.distance);
    const distances = scores.map((s) => s.distance);
    const median = distances[Math.floor(distances.length / 2)] ?? 0;
    const cutoff = median * thresholdMultiplier;
    const outliers = scores.filter((s) => s.distance > cutoff);

    console.log(`Compared ${scores.length} glass/gradient pairs`);
    console.log(`Median silhouette distance: ${median.toFixed(0)}`);
    console.log(`Flagging ${outliers.length} outliers (>${thresholdMultiplier}x median):\n`);

    for (const outlier of outliers) {
        console.log(
            `  ${outlier.name}: ${outlier.distance.toFixed(0)} (${(outlier.distance / median).toFixed(1)}x)`,
        );
    }

    if (outliers.length > 0) process.exit(1);
}

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