// Tests for the brand fonts manifest → @font-face generation (Task 608).
//
// brand.json may carry an optional `fonts` manifest mapping display/body
// roles to a font family and a set of self-hosted woff2 faces. bundle.js
// uses parseFontsManifest + renderFontFaceCss to emit @font-face blocks into
// brand-defaults.css so a non-default brand's declared fonts actually load.
// This is a permanent regression test in the installer suite (same pattern as
// premium-bundle-gate.test.ts).
import test from "node:test";
import assert from "node:assert/strict";
// @ts-expect-error - sibling .mjs without type declarations
import { parseFontsManifest, renderFontFaceCss, findMissingFontFiles } from "../../scripts/brand-fonts.mjs";
const REALAGENT_FONTS = {
    display: {
        family: "Playfair Display",
        faces: [
            { weight: 300, file: "playfair-display-300.woff2" },
            { weight: 400, file: "playfair-display-400.woff2" },
            { weight: 500, file: "playfair-display-500.woff2" },
        ],
    },
    body: {
        family: "Inter",
        faces: [
            { weight: 400, file: "inter-400.woff2" },
            { weight: 500, file: "inter-500.woff2" },
        ],
    },
};
test("parseFontsManifest: flattens roles into one entry per face", () => {
    const entries = parseFontsManifest(REALAGENT_FONTS);
    assert.equal(entries.length, 5);
    assert.deepEqual(entries[0], {
        role: "display",
        family: "Playfair Display",
        weight: 300,
        style: "normal",
        file: "playfair-display-300.woff2",
    });
    assert.deepEqual(entries[4], {
        role: "body",
        family: "Inter",
        weight: 500,
        style: "normal",
        file: "inter-500.woff2",
    });
});
test("parseFontsManifest: defaults style to normal, honours explicit style", () => {
    const entries = parseFontsManifest({
        display: {
            family: "Playfair Display",
            faces: [{ weight: 400, style: "italic", file: "pf-400-italic.woff2" }],
        },
    });
    assert.equal(entries.length, 1);
    assert.equal(entries[0].style, "italic");
});
test("parseFontsManifest: throws when a role is missing family", () => {
    assert.throws(() => parseFontsManifest({ display: { faces: [{ weight: 400, file: "x.woff2" }] } }), /family/i);
});
test("parseFontsManifest: throws when a role has no faces", () => {
    assert.throws(() => parseFontsManifest({ display: { family: "Playfair Display", faces: [] } }), /face/i);
});
test("parseFontsManifest: throws on a non-integer weight", () => {
    assert.throws(() => parseFontsManifest({ display: { family: "X", faces: [{ weight: "bold", file: "x.woff2" }] } }), /weight/i);
});
test("parseFontsManifest: throws on a face missing a file", () => {
    assert.throws(() => parseFontsManifest({ display: { family: "X", faces: [{ weight: 400 }] } }), /file/i);
});
test("parseFontsManifest: throws on unsafe characters in family or file", () => {
    assert.throws(() => parseFontsManifest({ display: { family: "X'}", faces: [{ weight: 400, file: "x.woff2" }] } }), /unsafe/i);
    assert.throws(() => parseFontsManifest({ display: { family: "X", faces: [{ weight: 400, file: "../x.woff2" }] } }), /unsafe/i);
});
test("renderFontFaceCss: emits one @font-face per entry with /brand/fonts URL", () => {
    const css = renderFontFaceCss(parseFontsManifest(REALAGENT_FONTS));
    const blocks = css.match(/@font-face/g) || [];
    assert.equal(blocks.length, 5);
    assert.match(css, /font-family: 'Playfair Display';/);
    assert.match(css, /font-weight: 300;/);
    assert.match(css, /src: url\('\/brand\/fonts\/playfair-display-300\.woff2'\) format\('woff2'\);/);
    assert.match(css, /font-display: swap;/);
    assert.match(css, /font-family: 'Inter';/);
});
test("renderFontFaceCss: empty entry list yields empty string", () => {
    assert.equal(renderFontFaceCss([]), "");
});
test("findMissingFontFiles: returns files whose path the predicate rejects", () => {
    const entries = parseFontsManifest(REALAGENT_FONTS);
    const present = new Set([
        "/fonts/playfair-display-300.woff2",
        "/fonts/playfair-display-400.woff2",
        "/fonts/inter-400.woff2",
        "/fonts/inter-500.woff2",
    ]);
    const missing = findMissingFontFiles(entries, "/fonts", (p) => present.has(p));
    assert.deepEqual(missing, ["playfair-display-500.woff2"]);
});
test("findMissingFontFiles: returns empty array when every face file exists", () => {
    const entries = parseFontsManifest(REALAGENT_FONTS);
    const missing = findMissingFontFiles(entries, "/fonts", () => true);
    assert.deepEqual(missing, []);
});
