import { describe, it, expect } from "vitest";
import { seedModellen, seedOnderdelen } from "./index";

// ── Algemene NL ↔ FR pariteitsbewaking ───────────────────────────────────────
// Het kantoor werkt tweetalig: elk model en elke clausule die in beide talen
// bestaat, moet zoveel mogelijk gelijk lopen. Deze test bewaakt dat — over de
// HELE bibliotheek, niet enkel de beschrijvingsclausule:
//
//  1. elke Franstalige clausule/model verwijst via `vertalingVanId` naar een
//     bestaande NL-bron;
//  2. paarsgewijze clausules hebben dezelfde hypothese-varianten met DEZELFDE
//     variant-id's (zodat één deterministische hypothesekeuze in beide talen
//     dezelfde variant selecteert) en dezelfde basistekst-aanwezigheid;
//  3. paarsgewijze modellen hebben dezelfde structuur (zelfde onderdelen in
//     dezelfde volgorde, op het -fr-achtervoegsel van de onderdeel-id na).
//
// Breekt deze test, dan zijn de talen uit elkaar gegroeid: vul de ontbrekende
// clausule/variant aan in de andere taal (desnoods voorlopig met de tekst van
// de andere taal en de markering "[TE VERTALEN]") zodat het gouden pad in beide
// talen blijft werken.

const onderdeelById = new Map(seedOnderdelen.map((o) => [o.id, o]));
const modelById = new Map(seedModellen.map((m) => [m.id, m]));

describe("bibliotheek — unieke ids", () => {
  // Dubbele ids geven onvoorspelbaar gedrag: find() pakt de eerste definitie,
  // een Map de laatste. Elke clausule en elk model bestaat dus exact één keer.
  it("elke clausule-id komt precies één keer voor", () => {
    const dubbels = seedOnderdelen
      .map((o) => o.id)
      .filter((id, i, all) => all.indexOf(id) !== i);
    expect(dubbels).toEqual([]);
  });

  it("elke model-id komt precies één keer voor", () => {
    const dubbels = seedModellen
      .map((m) => m.id)
      .filter((id, i, all) => all.indexOf(id) !== i);
    expect(dubbels).toEqual([]);
  });
});

const frOnderdelen = seedOnderdelen.filter((o) => o.taal === "fr" && o.vertalingVanId);
const frModellen = seedModellen.filter((m) => m.taal === "fr" && m.vertalingVanId);

describe("NL/FR pariteit — clausules (modelonderdelen)", () => {
  it("er zijn Franstalige clausules om te bewaken", () => {
    expect(frOnderdelen.length).toBeGreaterThan(0);
  });

  it.each(frOnderdelen.map((o) => [o.id, o.vertalingVanId!] as const))(
    "%s loopt gelijk met de NL-bron %s",
    (frId, nlId) => {
      const fr = onderdeelById.get(frId)!;
      const nl = onderdeelById.get(nlId);
      expect(nl, `NL-bron ${nlId} van ${frId} bestaat niet`).toBeDefined();
      // Variant-id's identiek (zelfde set, zelfde volgorde) — geen -fr-suffix op
      // variant-id's, want dan zou een gedeelde hypothesekeuze niet matchen.
      const nlVar = nl!.varianten.map((v) => v.id);
      const frVar = fr.varianten.map((v) => v.id);
      expect(frVar, `variant-id's van ${frId} wijken af van ${nlId}`).toEqual(nlVar);
      // Basistekst in beide talen aanwezig of in beide afwezig.
      expect(Boolean((fr.tekst ?? "").trim())).toBe(Boolean((nl!.tekst ?? "").trim()));
      // Zelfde categorie.
      expect(fr.categorie).toBe(nl!.categorie);
      // Zelfde modeltypes (toepasbaarOp): een clausule die in de ene taal in
      // een modeltype inzetbaar is, moet dat ook in de andere taal zijn.
      expect(
        [...(fr.toepasbaarOp ?? [])].sort(),
        `toepasbaarOp van ${frId} wijkt af van ${nlId}`
      ).toEqual([...(nl!.toepasbaarOp ?? [])].sort());
    }
  );
});

describe("NL/FR pariteit — modellen", () => {
  const strip = (id: string) => id.replace(/-fr$/, "");

  it.each(frModellen.map((m) => [m.id, m.vertalingVanId!] as const))(
    "%s heeft dezelfde structuur als de NL-bron %s",
    (frId, nlId) => {
      const fr = modelById.get(frId)!;
      const nl = modelById.get(nlId);
      expect(nl, `NL-bron ${nlId} van ${frId} bestaat niet`).toBeDefined();
      const nlS = nl!.structuur.map((s) => strip(s.onderdeelId));
      const frS = fr.structuur.map((s) => strip(s.onderdeelId));
      expect(frS, `structuur van ${frId} wijkt af van ${nlId}`).toEqual(nlS);
    }
  );
});
