// ── Gedeelde helper: queryparameters → ingevuld ontwerpdocument ─────────────
// Wordt gebruikt door app/api/modeldocumenten/[id]/route.ts (JSON-antwoord) en
// app/api/modeldocumenten/[id]/word/route.ts (.docx-antwoord), zodat de
// queryparameter- en facultatief-logica niet dupliceert (zie AGENTS.md).

import type { Modeldocument } from "@/data/modeldocumenten";
import {
  seedOnderdelen,
  standaardKeuzes,
  pasKeuzesToe,
  genereerDocument,
  stelModelSamen,
  extraheerParameters,
  canoniekeParameterNaam,
} from "@/data/modeldocumenten";
import { registreerGebruik } from "@/lib/gebruikslog";
import {
  kenmerkenNaarKeuzes,
  heldereTaalKeuzes,
  parseKenmerken,
  KENMERKEN_HANDLEIDING,
  type Ontwerpkenmerken,
} from "@/lib/dossier/kenmerken";

/**
 * Queryparameters met een eigen betekenis (geen invulwaarde voor een
 * {{parameter}}): alle deterministische kenmerken uit de handleiding (één bron
 * van waarheid — een nieuw kenmerk in de motor is hier automatisch
 * gereserveerd) plus de vaste stuurparameters.
 */
const GERESERVEERDE_PARAMS = new Set([
  ...KENMERKEN_HANDLEIDING.kenmerken.map((k) => k.naam as string),
  "facultatief", "taal", "notities", "voorbeeldset",
]);

/**
 * Leidt (optionele) structurele kenmerken af uit de query voor de
 * deterministische hypothesekeuze — via parseKenmerken, zodat élk kenmerk dat
 * de motor kent hier automatisch werkt (voorheen ontbraken o.a. epcAanwezig,
 * asbestAanwezig, overstromingVeilig, fiscaalRegime en wettelijkVoorkooprecht).
 */
function kenmerkenUitQuery(zoekParams: URLSearchParams): Ontwerpkenmerken {
  const rauw: Record<string, unknown> = {};
  for (const uitleg of KENMERKEN_HANDLEIDING.kenmerken) {
    const waarde = zoekParams.get(uitleg.naam as string);
    if (waarde !== null) rauw[uitleg.naam as string] = waarde;
  }
  // Ongeldige waarden worden hier stil genegeerd (zelfde gedrag als voorheen):
  // de queryvariant is bewust vergevingsgezind; de POST-variant
  // (genereerOntwerpUitKenmerken) meldt problemen wél expliciet.
  return parseKenmerken(rauw).kenmerken;
}

export interface OntwerpUitQueryResultaat {
  ontwerp: string;
  /** De ingevulde {{parameter}}-waarden uit de query (voor o.a. het omkaderde vak). */
  waarden: Record<string, string>;
  opgenomenFacultatief: string[];
  genegeerdFacultatief: string[];
  /**
   * Invulparameters uit de query die niet als {{parameter}} in het model
   * voorkomen (doorgaans een typfout van de agent). Voorheen verdwenen die
   * stilzwijgend en bleef het veld als [AAN TE VULLEN] staan zonder enige
   * feedback.
   */
  genegeerdeParameters: string[];
  heeftInvulparams: boolean;
  heeftFacultatiefParam: boolean;
  /** Vrije, door de gebruiker aangeleverde informatie (query "notities"), zonder eigen {{parameter}}. */
  notitiesGebruiker?: string;
}

/**
 * Leidt uit de queryparameters van een request de invulwaarden en gevraagde
 * facultatieve onderdelen af, en genereert daarmee het ingevulde ontwerp.
 */
export async function ontwerpUitQuery(
  model: Modeldocument,
  zoekParams: URLSearchParams
): Promise<OntwerpUitQueryResultaat> {
  const waarden: Record<string, string> = {};
  for (const [key, waarde] of zoekParams.entries()) {
    if (GERESERVEERDE_PARAMS.has(key)) continue;
    waarden[key] = waarde;
  }

  const facultatiefParam = zoekParams.get("facultatief");
  const gevraagdeFacultatief = facultatiefParam === null
    ? []
    : facultatiefParam.split(",").map((v) => v.trim()).filter(Boolean);

  // Optionele structurele kenmerken (gewest/goedType/gebruik/metKrediet) → de
  // deterministische hypothesekeuze (bv. juiste gewestvariant, mede-eigendom,
  // brandverzekering). Zonder kenmerken blijft het gedrag identiek (alle
  // hypotheses ter keuze, standaardKeuzes).
  const kenmerken = kenmerkenUitQuery(zoekParams);
  const keuzes =
    Object.keys(kenmerken).length > 0
      ? pasKeuzesToe(model, [...kenmerkenNaarKeuzes(kenmerken), ...heldereTaalKeuzes(kenmerken)])
      : standaardKeuzes(model);
  const opgenomenFacultatief: string[] = [];
  const genegeerdFacultatief: string[] = [];
  for (const onderdeelId of gevraagdeFacultatief) {
    const index = model.structuur.findIndex(
      (s) => s.onderdeelId === onderdeelId && !s.verplicht
    );
    if (index === -1) {
      genegeerdFacultatief.push(onderdeelId);
      continue;
    }
    keuzes[index] = { ...keuzes[index], opnemen: true };
    opgenomenFacultatief.push(onderdeelId);
  }
  for (const onderdeelId of genegeerdFacultatief) {
    await registreerGebruik({ type: "genegeerd_facultatief_onderdeel", waarde: `${model.id}:${onderdeelId}` });
  }

  // Typfout-detectie: welke aangeleverde invulwaarden matchen met geen enkele
  // {{parameter}} in het (volledige, alle hypotheses omvattende) model?
  const bekendeParameters = new Set(extraheerParameters(stelModelSamen(model, seedOnderdelen)));
  // Een waarde onder een aliasnaam (parameter-register.ts) is géén typfout:
  // ze vult de canonieke placeholder via de aliasresolutie in vulParametersIn.
  const genegeerdeParameters = Object.keys(waarden).filter(
    (naam) => !bekendeParameters.has(naam) && !bekendeParameters.has(canoniekeParameterNaam(naam))
  );
  for (const naam of genegeerdeParameters) {
    await registreerGebruik({ type: "onbekende_parameter", waarde: `${model.id}:${naam}` });
  }

  const ontwerp = genereerDocument(model, seedOnderdelen, keuzes, waarden);

  return {
    ontwerp,
    waarden,
    opgenomenFacultatief,
    genegeerdFacultatief,
    genegeerdeParameters,
    heeftInvulparams: Object.keys(waarden).length > 0,
    heeftFacultatiefParam: facultatiefParam !== null,
    notitiesGebruiker: zoekParams.get("notities") ?? undefined,
  };
}
