// ── Cross-module handoff ─────────────────────────────────────────────────────
// Getypeerd contract voor parameteroverdracht tussen modules via
// sessionStorage. Schrijvende en lezende module importeren hetzelfde type,
// zodat veldwijzigingen door de compiler worden afgedwongen.
//
// Elke brug is een aanroep van de éne fabriek `maakHandoff` (sleutel +
// validator): de mechaniek — stille try/catch rond sessionStorage, eenmalig
// lezen-en-wissen, JSON-parsing — staat één keer en kan niet per brug
// divergeren. Een nieuwe brug toevoegen = interface + validator + één
// fabriek-aanroep; het rondje wordt bewaakt door lib/handoff.test.ts.

import type { GoedeType, Relatie } from "@/data/belastingen";
import { actieveAkteTypen, type AkteType } from "@/data/ereloon";
import type { Begunstigde } from "@/components/BegunstigdenEditor";

/**
 * Bouwt één handoff-brug: `schrijf` bewaart het object onder de sleutel
 * (stil falend wanneer sessionStorage niet beschikbaar is — de lezende module
 * valt dan terug op haar defaults); `lees` haalt het op, wist het meteen
 * (eenmalig gebruik) en laat de validator de ruwe JSON beoordelen — die
 * retourneert het gevalideerde object of null bij een onbruikbare inhoud.
 */
function maakHandoff<T>(
  sleutel: string,
  valideer: (ruw: Partial<T>) => T | null
): { schrijf: (h: T) => void; lees: () => T | null } {
  return {
    schrijf(h: T): void {
      try {
        sessionStorage.setItem(sleutel, JSON.stringify(h));
      } catch {
        /* sessionStorage niet beschikbaar — handoff valt stil terug op defaults */
      }
    },
    lees(): T | null {
      try {
        const raw = sessionStorage.getItem(sleutel);
        if (!raw) return null;
        sessionStorage.removeItem(sleutel);
        const ruw: unknown = JSON.parse(raw);
        if (!ruw || typeof ruw !== "object") return null;
        return valideer(ruw as Partial<T>);
      } catch {
        return null;
      }
    },
  };
}

// ── Schenking: belastingmodule → aktekostenmodule ────────────────────────────

/**
 * Parameteroverdracht van de schenkbelastingmodule (`app/belasting`) naar de
 * aktekostenmodule (`app/ereloon`) wanneer de notaris vanuit een
 * schenkingssimulatie de aktekosten wil bekijken.
 *
 * - `akteType`/`bedrag`/`relatie` zijn altijd aanwezig: eenvoudige fallback
 *   voor single-begunstigde scenario's (initialiseert akteType, bedrag en
 *   relatie van de eerste/enige begunstigde).
 * - `begunstigden` is optioneel en enkel aanwezig wanneer de
 *   belastingmodule in "meerdere begunstigden"-modus stond — de
 *   ereloonmodule gebruikt dit om `meerdereBegunstigdenSchenk`/
 *   `begunstigdenSchenk` te initialiseren.
 * - `aantalSchenkers` is optioneel en geeft het aantal overdragende partijen
 *   door — gebruikt als default voor `aantalPandregister` en voor
 *   retributies "per overdrager" (heeftAantal) in de aktekostenmodule.
 */
export interface SchenkingHandoff {
  akteType: "schenking-onroerend" | "schenking-roerend";
  bedrag: string;
  relatie: Relatie;
  /** Aanwezig wanneer de belastingmodule in "meerdere begunstigden"-modus stond. */
  begunstigden?: Begunstigde[];
  /** Aantal overdragende partijen (schenkers) — voor pandregister/retributies "per overdrager". */
  aantalSchenkers?: number;
}

const schenking = maakHandoff<SchenkingHandoff>("notaryai_schenking_handoff", (h) => {
  if (h.akteType !== "schenking-onroerend" && h.akteType !== "schenking-roerend") return null;
  return {
    akteType: h.akteType,
    bedrag: typeof h.bedrag === "string" ? h.bedrag : "",
    relatie: (h.relatie as Relatie) ?? "rechte_lijn_partner",
    begunstigden: Array.isArray(h.begunstigden) ? h.begunstigden : undefined,
    aantalSchenkers:
      typeof h.aantalSchenkers === "number" && h.aantalSchenkers > 0 ? h.aantalSchenkers : undefined,
  };
});

export const schrijfSchenkingHandoff = schenking.schrijf;
/** Leest de handoff en wist hem meteen (eenmalig gebruik). */
export const leesSchenkingHandoff = schenking.lees;

// ── Modeldocument: modeldocumentenmodule → AI-prompts (Modus A) ──────────────

/** Gegenereerd modeldocument, doorgegeven aan de AI-prompts module (Modus A). */
export interface ModeldocumentHandoff {
  titel: string;
  tekst: string;
}

const modeldocument = maakHandoff<ModeldocumentHandoff>("notaryai_modeldocument_handoff", (h) => {
  if (typeof h.tekst !== "string" || !h.tekst) return null;
  return { titel: typeof h.titel === "string" ? h.titel : "Modeldocument", tekst: h.tekst };
});

export const schrijfModeldocumentHandoff = modeldocument.schrijf;
/** Leest de handoff en wist hem meteen (eenmalig gebruik). */
export const leesModeldocumentHandoff = modeldocument.lees;

// ── Aktekosten: dossier → aktekostenmodule ───────────────────────────────────

/**
 * Parameteroverdracht van een dossier (`app/dossier`) naar de
 * aktekostenmodule (`app/ereloon`), zodat de notaris vanuit een lopend
 * dossier meteen de indicatieve afrekening kan bekijken zonder het bedrag
 * opnieuw te moeten intikken. `akteType` mag elk in de rekenmodule ACTIEF
 * akteType zijn (verkoop, schenking, hypotheek/kredietakte, …) — de
 * validator weigert types die de ereloonmodule (nog) niet actief rekent.
 */
export interface AktekostenHandoff {
  akteType: AkteType;
  bedrag: string;
}

const aktekosten = maakHandoff<AktekostenHandoff>("notaryai_aktekosten_handoff", (h) => {
  if (typeof h.akteType !== "string" || !actieveAkteTypen.includes(h.akteType)) return null;
  if (typeof h.bedrag !== "string" || !h.bedrag) return null;
  return { akteType: h.akteType, bedrag: h.bedrag };
});

export const schrijfAktekostenHandoff = aktekosten.schrijf;
/** Leest de handoff en wist hem meteen (eenmalig gebruik). */
export const leesAktekostenHandoff = aktekosten.lees;

// ── Ontwerpakte: dossier → modeldocumentenmodule ─────────────────────────────

/**
 * Een uit het dossier afgeleide keuze voor één structuuronderdeel: welke
 * hypothese-variant te kiezen en/of of een facultatief onderdeel op te nemen.
 */
export interface OntwerpKeuze {
  onderdeelId: string;
  /** Te kiezen hypothese-variant; weglaten = alle hypotheses behouden. */
  variantId?: string;
  /** Facultatief onderdeel toch opnemen. */
  opnemen?: boolean;
  /**
   * True wanneer de (niet-)opname deterministisch beslist werd op basis van
   * een reeds gekend dossierfeit — onderdrukt de generieke "facultatief
   * onderdeel, enkel van toepassing indien …"-markering (zie GeneratieKeuze
   * in data/modeldocumenten/samenstellen.ts).
   */
  conditieBevestigd?: boolean;
}

/**
 * Parameteroverdracht van een dossier (`app/dossier`) naar de
 * modeldocumentenmodule (`app/modeldocumenten`), zodat de notaris vanuit een
 * dossier rechtstreeks een ontwerpakte kan genereren met de uit het dossier
 * gekende parameters al voorgevuld. `akteType` selecteert het passende model;
 * `parameterwaarden` zijn de uit het dossier afgeleide {{parameter}}-waarden
 * (zie lib/dossier/parameters.ts).
 */
export interface OntwerpakteHandoff {
  akteType: string;
  parameterwaarden: Record<string, string>;
  /** Korte omschrijving van het dossier (bv. het adres), louter voor weergave. */
  dossierLabel: string;
  /**
   * Eén identificatie-herhaling per partij, zodat per-partij hernomen
   * onderdelen voor elke partij afzonderlijk en voorgevuld worden gegenereerd
   * (zie lib/dossier/parameters.ts → dossierNaarPartijHerhalingen).
   */
  partijHerhalingen?: { label?: string; waarden: Record<string, string> }[];
  /** Uit het dossier afgeleide hypothese-/opname-keuzes per onderdeel. */
  keuzes?: OntwerpKeuze[];
}

const ontwerpakte = maakHandoff<OntwerpakteHandoff>("notaryai_ontwerpakte_handoff", (h) => {
  if (typeof h.akteType !== "string" || !h.akteType) return null;
  return {
    akteType: h.akteType,
    parameterwaarden: h.parameterwaarden && typeof h.parameterwaarden === "object" ? h.parameterwaarden : {},
    dossierLabel: typeof h.dossierLabel === "string" ? h.dossierLabel : "",
    partijHerhalingen: Array.isArray(h.partijHerhalingen) ? h.partijHerhalingen : undefined,
    keuzes: Array.isArray(h.keuzes) ? h.keuzes : undefined,
  };
});

export const schrijfOntwerpakteHandoff = ontwerpakte.schrijf;
/** Leest de handoff en wist hem meteen (eenmalig gebruik). */
export const leesOntwerpakteHandoff = ontwerpakte.lees;

// ── Modelbrief: dossier → modelbrievenmodule ─────────────────────────────────

/**
 * Parameteroverdracht van een dossier (`app/dossier`) naar de
 * modelbrievenmodule (`app/modelbrieven`), zodat de notaris vanuit een
 * dossier rechtstreeks een modelmail kan opstellen met de uit het dossier
 * gekende parameters (partijen, prijs, ontbrekende stukken) al voorgevuld.
 * `categorie` selecteert het hoofdstuk van de modelbrievenbibliotheek
 * waarin de notaris meteen terechtkomt.
 */
export interface ModelbriefHandoff {
  categorie: string;
  parameterwaarden: Record<string, string>;
  /** Korte omschrijving van het dossier (bv. het adres), louter voor weergave. */
  dossierLabel: string;
}

const modelbrief = maakHandoff<ModelbriefHandoff>("notaryai_modelbrief_handoff", (h) => {
  if (typeof h.categorie !== "string" || !h.categorie) return null;
  return {
    categorie: h.categorie,
    parameterwaarden: h.parameterwaarden && typeof h.parameterwaarden === "object" ? h.parameterwaarden : {},
    dossierLabel: typeof h.dossierLabel === "string" ? h.dossierLabel : "",
  };
});

export const schrijfModelbriefHandoff = modelbrief.schrijf;
/** Leest de handoff en wist hem meteen (eenmalig gebruik). */
export const leesModelbriefHandoff = modelbrief.lees;

// ── Belasting: dossier → belastingmodule ─────────────────────────────────────

/**
 * Parameteroverdracht van een schenkings- of nalatenschapsdossier
 * (`app/dossier`) naar de belastingmodule (`app/belasting`), zodat de
 * notaris vanuit het dossier meteen de schenk-/erfbelasting kan simuleren
 * met de gekende belastbare waarde, verwantschap en aard van het goed al
 * voorgevuld.
 */
export interface BelastingHandoff {
  bedrag: string;
  relatie: Relatie;
  goedType: GoedeType;
  /** Andere goederen van de nalatenschap, indien gekend (basis voor de progressiviteit). */
  andereGoederen?: string;
  /** Korte omschrijving van het dossier, louter voor weergave. */
  dossierLabel: string;
}

const belasting = maakHandoff<BelastingHandoff>("notaryai_belasting_handoff", (h) => {
  if (typeof h.bedrag !== "string" || !h.bedrag) return null;
  return {
    bedrag: h.bedrag,
    relatie: (h.relatie as Relatie) ?? "rechte_lijn_partner",
    goedType: (h.goedType as GoedeType) ?? "onroerend",
    andereGoederen: typeof h.andereGoederen === "string" ? h.andereGoederen : undefined,
    dossierLabel: typeof h.dossierLabel === "string" ? h.dossierLabel : "",
  };
});

export const schrijfBelastingHandoff = belasting.schrijf;
/** Leest de handoff en wist hem meteen (eenmalig gebruik). */
export const leesBelastingHandoff = belasting.lees;
