// ── Schema-guard op de seed-bibliotheek ──────────────────────────────────────
// Semantische validatie bovenop wat tsc al afdwingt: TypeScript garandeert dat
// verplichte velden BESTAAN, maar niet dat ze zinvol gevuld zijn (lege
// string), dat ids uniek zijn, of dat verwijzingen (vertalingVanId,
// structuur → onderdeel) ergens naartoe wijzen. Zo'n fout betekende voorheen
// een clausule die stilzwijgend ontbrak of een [ONTBREKEND]-blok in een
// gegenereerde akte, pas zichtbaar bij een latere, aparte test.
//
// assertSeedBibliotheek draait bij het inladen van de datalaag (zie
// data/modeldocumenten/index.ts) en laat dev/test/build ONMIDDELLIJK falen met
// alle problemen in één melding. valideerSeedBibliotheek is de pure kern,
// apart testbaar en herbruikbaar voor runtime-data (gebruikersbibliotheek).

import type { Modeldocument, Modelonderdeel } from "./types";

/** Leeg of enkel witruimte? (tsc dwingt bestaan af, niet zinvolle inhoud) */
function leeg(waarde: string | undefined): boolean {
  return waarde === undefined || waarde.trim() === "";
}

/**
 * Valideert de bibliotheek en geeft alle gevonden problemen terug (leeg =
 * geldig). Pure functie: geen throw, geen logging — de aanroeper beslist.
 */
export function valideerSeedBibliotheek(
  onderdelen: Modelonderdeel[],
  modellen: Modeldocument[]
): string[] {
  const problemen: string[] = [];

  // ── Onderdelen ──
  const onderdeelIds = new Set<string>();
  for (const o of onderdelen) {
    const wie = `onderdeel "${o.id || "(zonder id)"}"`;
    for (const [veld, waarde] of [
      ["id", o.id],
      ["titel", o.titel],
      ["versie", o.versie],
      ["datum", o.datum],
    ] as const) {
      if (leeg(waarde)) problemen.push(`${wie}: verplicht veld "${veld}" is leeg.`);
    }
    if (o.id) {
      if (onderdeelIds.has(o.id)) problemen.push(`dubbel onderdeel-id "${o.id}".`);
      onderdeelIds.add(o.id);
    }
    if (leeg(o.tekst) && o.varianten.length === 0) {
      problemen.push(`${wie}: geen basistekst én geen varianten — het onderdeel heeft geen inhoud.`);
    }
    const variantIds = new Set<string>();
    for (const v of o.varianten) {
      if (leeg(v.id)) problemen.push(`${wie}: variant zonder id.`);
      else {
        if (variantIds.has(v.id)) problemen.push(`${wie}: dubbel variant-id "${v.id}".`);
        variantIds.add(v.id);
      }
      if (leeg(v.hypothese)) problemen.push(`${wie}, variant "${v.id}": "hypothese" is leeg.`);
      if (leeg(v.tekst)) problemen.push(`${wie}, variant "${v.id}": "tekst" is leeg.`);
    }
    if (o.wetsbasis?.some((w) => leeg(w))) {
      problemen.push(`${wie}: "wetsbasis" bevat een lege vermelding.`);
    }
  }
  for (const o of onderdelen) {
    if (o.vertalingVanId === undefined) continue;
    const wie = `onderdeel "${o.id}"`;
    if (o.vertalingVanId === o.id) problemen.push(`${wie}: vertalingVanId verwijst naar zichzelf.`);
    else if (!onderdeelIds.has(o.vertalingVanId)) {
      problemen.push(`${wie}: vertalingVanId "${o.vertalingVanId}" bestaat niet in de bibliotheek.`);
    }
  }

  // ── Modellen ──
  const modelIds = new Set<string>();
  for (const m of modellen) {
    const wie = `model "${m.id || "(zonder id)"}"`;
    for (const [veld, waarde] of [
      ["id", m.id],
      ["titel", m.titel],
      ["akteType", m.akteType],
      ["versie", m.versie],
      ["datum", m.datum],
    ] as const) {
      if (leeg(waarde)) problemen.push(`${wie}: verplicht veld "${veld}" is leeg.`);
    }
    if (m.id) {
      if (modelIds.has(m.id)) problemen.push(`dubbel model-id "${m.id}".`);
      modelIds.add(m.id);
    }
    if (m.structuur.length === 0) problemen.push(`${wie}: lege structuur — het model bevat geen onderdelen.`);
    for (const item of m.structuur) {
      if (!onderdeelIds.has(item.onderdeelId)) {
        problemen.push(
          `${wie}: structuur verwijst naar onbestaand onderdeel "${item.onderdeelId}" — die clausule ontbreekt stilzwijgend in elk gegenereerd document.`
        );
      }
    }
  }
  for (const m of modellen) {
    if (m.vertalingVanId === undefined) continue;
    const wie = `model "${m.id}"`;
    if (m.vertalingVanId === m.id) problemen.push(`${wie}: vertalingVanId verwijst naar zichzelf.`);
    else if (!modelIds.has(m.vertalingVanId)) {
      problemen.push(`${wie}: vertalingVanId "${m.vertalingVanId}" bestaat niet in de bibliotheek.`);
    }
  }

  return problemen;
}

/** Laadcontrole: gooit één fout met álle problemen zodra de seed-data ongeldig is. */
export function assertSeedBibliotheek(onderdelen: Modelonderdeel[], modellen: Modeldocument[]): void {
  const problemen = valideerSeedBibliotheek(onderdelen, modellen);
  if (problemen.length > 0) {
    throw new Error(
      `Seed-bibliotheek ongeldig (${problemen.length} probleem/problemen):\n- ${problemen.join("\n- ")}`
    );
  }
}
