// ── AUT-O4 · Dossier-levenscyclus-toestandsmachine (laag 2) ──────────────────
// Vandaag kent een dossier zes compromis-gerichte statussen (`DossierStatus` in
// types.ts). Voor volledige autonomie moet een dossier de HELE keten kunnen
// doorlopen — intake → compliance → opzoekingen → ontwerp → nazicht →
// ondertekening → formaliteiten → financiële afhandeling → afgesloten — met een
// expliciete "volgende stap"-motor en termijnbewaking. Dit bestand legt die
// toestandsmachine vast als een pure, bewaakte primitieve.
//
// ── Ontwerpbeslissingen (de dragende Opus-keuzes) ───────────────────────────
// 1. NIEUW MODEL NAAST HET BESTAANDE, NIET IN DE PLAATS. De rijke levenscyclus
//    (`Dossierfase`) leeft hier; de bestaande `DossierStatus` blijft ongemoeid
//    (ze wordt breed gebruikt in app/tests). `faseVanStatus` mapt de oude naar
//    de nieuwe, zodat beide coëxisteren. Het effectief vervangen van
//    DossierStatus is een latere Sonnet-stap (AUT-S3) — geen breuk nu.
// 2. EXPLICIETE, BEWAAKTE OVERGANGEN. `FASE_OVERGANGEN` is de enige bron van
//    toegelaten overgangen; `magOvergaan` verbiedt sprongen die het proces
//    zouden overslaan. Zo kan de "volgende stap"-motor nooit een fase overslaan
//    die (bv.) compliance of een opzoeking bevat.
// 3. HET AMBTELIJK SLUITSTUK ZIT IN DE KETEN MAAR WORDT NIET GEAUTOMATISEERD.
//    De fase "ondertekening" (het verlijden) is `ambtelijk: true`: de motor
//    bereidt alles voor en draagt daar over aan de notaris (laag 8) — hij is
//    geen stap die Notary.AI zelf uitvoert.
// 4. PUUR & DETERMINISTISCH. Termijnen worden beoordeeld tegen een meegegeven
//    referentiedatum (geen `Date.now()`), zodat alles testbaar blijft.

import type { DossierStatus } from "./types";

/** De volledige levenscyclus van een dossier, in natuurlijke volgorde. */
export const DOSSIERFASEN = [
  "intake", // bronstukken inlezen, opdracht + partijen vastleggen (laag 1)
  "compliance", // AML/KYC/UBO/sancties (laag 3)
  "opzoekingen", // externe opzoekingen (laag 3)
  "ontwerp", // ontwerp + mails + afrekening opstellen (laag 4)
  "nazicht-validatie", // de notaris leest na en valideert het werkdocument
  "ondertekening", // het verlijden — AMBTELIJK, door de notaris (laag 8)
  "formaliteiten", // registratie, overschrijving, databanken (laag 5)
  "financiele-afhandeling", // derdengelden, afrekening, doorstorting (laag 6)
  "afgesloten", // gearchiveerd, afgewerkt
] as const;

export type Dossierfase = (typeof DOSSIERFASEN)[number];

/** Toegelaten volgende fasen per fase (de bewaakte overgangstabel). Grotendeels
 * lineair; enkele bewuste sprongen (een dossier zonder opzoekingen kan van
 * compliance naar ontwerp). Een lege lijst = eindfase. */
export const FASE_OVERGANGEN: Record<Dossierfase, Dossierfase[]> = {
  intake: ["compliance"],
  compliance: ["opzoekingen", "ontwerp"],
  opzoekingen: ["ontwerp"],
  ontwerp: ["nazicht-validatie"],
  "nazicht-validatie": ["ontwerp", "ondertekening"], // terug naar ontwerp bij correcties
  ondertekening: ["formaliteiten"],
  formaliteiten: ["financiele-afhandeling"],
  "financiele-afhandeling": ["afgesloten"],
  afgesloten: [],
};

/** Fasen die de notaris persoonlijk uitvoert (ambtelijk voorbehoud); de motor
 * bereidt voor en draagt over, maar voert ze niet zelf uit. */
export const AMBTELIJKE_FASEN: ReadonlySet<Dossierfase> = new Set(["ondertekening"]);

/** De toegelaten volgende fasen vanuit `fase`. */
export function volgendeFasen(fase: Dossierfase): Dossierfase[] {
  return FASE_OVERGANGEN[fase];
}

/** Is de overgang van → naar toegelaten volgens de toestandsmachine? */
export function magOvergaan(van: Dossierfase, naar: Dossierfase): boolean {
  return FASE_OVERGANGEN[van].includes(naar);
}

/** Is dit een eindfase (geen verdere overgangen)? */
export function isEindfase(fase: Dossierfase): boolean {
  return FASE_OVERGANGEN[fase].length === 0;
}

/** Voert de notaris deze fase persoonlijk uit (ambtelijk voorbehoud)? */
export function isAmbtelijkeFase(fase: Dossierfase): boolean {
  return AMBTELIJKE_FASEN.has(fase);
}

/** Mapt de bestaande, compromis-gerichte `DossierStatus` op een levenscyclusfase,
 * zodat het nieuwe model naast het oude kan bestaan (ontwerpbeslissing 1). */
export function faseVanStatus(status: DossierStatus): Dossierfase {
  switch (status) {
    case "compromis-ontvangen":
      return "intake";
    case "opzoekingen-lopend":
      return "opzoekingen";
    case "ontwerp-in-opmaak":
      return "ontwerp";
    case "ontwerp-verstuurd":
      return "nazicht-validatie";
    case "klaar-voor-akte":
      return "ondertekening";
    case "verleden":
      return "formaliteiten";
  }
}

// ── Termijnbewaking ──────────────────────────────────────────────────────────

/** Eén te bewaken termijn (bv. compromis → akte binnen vier maanden). */
export interface Termijn {
  omschrijving: string;
  /** Vervaldatum als ISO "JJJJ-MM-DD". */
  vervaldatum: string;
}

export type TermijnStatus = "ok" | "nabij" | "verstreken";

/**
 * Beoordeelt een termijn tegen een meegegeven referentiedatum (puur, geen
 * `Date.now()`): "verstreken" na de vervaldag, "nabij" binnen `nabijDagen`
 * ervoor (standaard 14), anders "ok". Datums als ISO "JJJJ-MM-DD".
 */
export function termijnStatus(termijn: Termijn, vandaag: string, nabijDagen = 14): TermijnStatus {
  const dag = 24 * 60 * 60 * 1000;
  const resterend = Math.floor((Date.parse(termijn.vervaldatum) - Date.parse(vandaag)) / dag);
  if (resterend < 0) return "verstreken";
  if (resterend <= nabijDagen) return "nabij";
  return "ok";
}

/** Berekent een vervaldatum als `maanden` na een startdatum (beide ISO
 * "JJJJ-MM-DD"). Klemt de dag binnen de doelmaand (bv. 31 jan + 1 maand → 28/29
 * feb) zodat er nooit een ongeldige datum ontstaat. */
export function vervaldatumNaMaanden(startdatum: string, maanden: number): string {
  const d = new Date(`${startdatum}T00:00:00.000Z`);
  const dag = d.getUTCDate();
  d.setUTCDate(1);
  d.setUTCMonth(d.getUTCMonth() + maanden);
  const laatsteDag = new Date(Date.UTC(d.getUTCFullYear(), d.getUTCMonth() + 1, 0)).getUTCDate();
  d.setUTCDate(Math.min(dag, laatsteDag));
  return d.toISOString().slice(0, 10);
}
