// ── AUT-S3 · Levenscyclus-motor: de "volgende stap" (laag 2) ─────────────────
// De motor die een dossier door de AUT-O4-toestandsmachine voortstuwt: gegeven
// de huidige fase, het volledigheidsrapport (AUT-S2) en de termijnen, bepaalt
// hij de aanbevolen volgende fase, of Notary.AI die autonoom mag voorbereiden,
// en welke actie openstaat. Puur en deterministisch (referentiedatum als
// parameter, geen `Date.now()`), zodat de dossierregie hem overal kan aanroepen.
//
// ── Ontwerpbeslissingen ─────────────────────────────────────────────────────
// 1. DEFAULT-DENY OP DE POORT (drie tiers, zoals AGENTS.md). Elke fase heeft een
//    poortsoort: "data" (de motor beoordeelt ze uit de dossiergegevens),
//    "notaris" (een persoonlijke beslissing — AML-go, validatie, doorstorting —
//    die NOOIT autonoom is) of "ambtelijk" (het verlijden zelf, de
//    voorbehoudgrens). Enkel "data"-fasen kunnen `klaarVoorOvergang` worden.
// 2. FASE-SPECIFIEKE RIJPHEID. Ontbrekende opzoekingsstukken mogen intake niet
//    blokkeren (die komen pas in de opzoekingenfase binnen), maar blokkeren wél
//    de overgang opzoekingen→ontwerp. Een kritieke tegenstrijdigheid blokkeert
//    altijd.
// 3. GEEN NIEUWE WAARHEID. De motor hergebruikt faseVanStatus/volgendeFasen
//    (AUT-O4) en stelVolledigheidsrapportSamen (AUT-S2); hij beslist enkel de
//    volgende stap, hij herberekent niets.

import type { Dossier } from "./types";
import type { ExtractieResultaat } from "./perceptie";
import {
  faseVanStatus,
  volgendeFasen,
  termijnStatus,
  vervaldatumNaMaanden,
  DOSSIERFASEN,
  type Dossierfase,
  type Termijn,
  type TermijnStatus,
} from "./levenscyclus";
import { stelVolledigheidsrapportSamen, type Volledigheidsrapport } from "./volledigheidsrapport";

/** Wie bewaakt de overgang uit deze fase? */
export type Poortsoort = "data" | "notaris" | "ambtelijk";

/** Poortsoort per fase (default-deny: enkel "data"-fasen kunnen autonoom door). */
export const FASE_POORT: Record<Dossierfase, Poortsoort> = {
  intake: "data",
  compliance: "notaris", // AML/KYC-go is persoonlijk aan de notaris (AUT-O6)
  opzoekingen: "data",
  ontwerp: "data",
  "nazicht-validatie": "notaris", // de notaris valideert het werkdocument
  ondertekening: "ambtelijk", // het verlijden — de voorbehoudgrens
  formaliteiten: "data",
  "financiele-afhandeling": "notaris", // doorstorting is nooit autonoom (AUT-O7)
  afgesloten: "data",
};

/** Een termijn mét zijn beoordeling tegen de referentiedatum. */
export interface BeoordeeldeTermijn extends Termijn {
  status: TermijnStatus;
}

/** De uitkomst van de motor: wat is de volgende stap voor dit dossier? */
export interface VolgendeStap {
  huidigeFase: Dossierfase;
  /** De aanbevolen volgende fase (vooruit in de keten), of null in een eindfase. */
  aanbevolenFase: Dossierfase | null;
  /** Mag Notary.AI de overgang autonoom voorbereiden/uitvoeren? Enkel bij een "data"-poort én voldoende rijpheid. */
  klaarVoorOvergang: boolean;
  /** Vereist de volgende stap de notaris (notaris-poort of ambtelijk sluitstuk)? */
  vereistNotaris: boolean;
  /** De ambtelijke handeling zelf (het verlijden) — nooit geautomatiseerd. */
  ambtelijk: boolean;
  /** Mens-leesbare volgende actie. */
  actie: string;
  /** Waarom (nog) niet klaar — de blokkerende punten uit het rapport. */
  blokkades: string[];
  rapport: Volledigheidsrapport;
  termijnen: BeoordeeldeTermijn[];
}

/**
 * Bepaalt de volgende stap voor een dossier tegen een referentiedatum `vandaag`
 * (ISO "JJJJ-MM-DD"). Geef optioneel de perceptie-extractie mee (AUT-O3) zodat
 * onleesbare bronnen in het rapport meewegen. Puur.
 */
export function bepaalVolgendeStap(
  dossier: Dossier,
  vandaag: string,
  opties?: { extractie?: ExtractieResultaat }
): VolgendeStap {
  return bepaalVolgendeStapVanaf(dossier, faseVanStatus(dossier.status), vandaag, opties);
}

/**
 * Zoals `bepaalVolgendeStap`, maar met een expliciet meegegeven `huidigeFase`
 * i.p.v. de fase afgeleid uit `dossier.status`. Zo kan de orkestratie
 * (orkestratie.ts) een volledige autonome doorloop simuleren door fase na fase
 * te evalueren zonder de dossierstatus te muteren. De feiten (rapport,
 * termijnen) zijn faseonafhankelijk en worden per aanroep opnieuw berekend.
 */
export function bepaalVolgendeStapVanaf(
  dossier: Dossier,
  huidigeFase: Dossierfase,
  vandaag: string,
  opties?: { extractie?: ExtractieResultaat }
): VolgendeStap {
  const rapport = stelVolledigheidsrapportSamen(dossier, opties?.extractie);
  const termijnen = bepaalTermijnen(dossier, vandaag);
  const aanbevolenFase = kiesPrimaireVolgende(huidigeFase);
  // De poort bewaakt de overgang UIT de huidige fase (bv. het verlijden uit
  // "ondertekening" is ambtelijk); daarom FASE_POORT[huidigeFase].
  const poort = FASE_POORT[huidigeFase];

  const ambtelijk = aanbevolenFase !== null && poort === "ambtelijk";
  const vereistNotaris = aanbevolenFase !== null && (poort === "notaris" || poort === "ambtelijk");

  const klaarVoorOvergang = aanbevolenFase !== null && poort === "data" && faseIsRijp(huidigeFase, dossier, rapport);
  const blokkades = klaarVoorOvergang || vereistNotaris ? [] : rapport.punten.filter((p) => p.blokkerend).map((p) => p.omschrijving);
  const actie = bepaalActie(huidigeFase, aanbevolenFase, poort, klaarVoorOvergang);

  return { huidigeFase, aanbevolenFase, klaarVoorOvergang, vereistNotaris, ambtelijk, actie, blokkades, rapport, termijnen };
}

/** De aanbevolen volgende fase: de vooruit-optie (verst in de keten), of null in een eindfase. */
function kiesPrimaireVolgende(fase: Dossierfase): Dossierfase | null {
  const opties = volgendeFasen(fase).filter((f) => DOSSIERFASEN.indexOf(f) > DOSSIERFASEN.indexOf(fase));
  if (opties.length === 0) return null;
  return opties.reduce((verst, f) => (DOSSIERFASEN.indexOf(f) > DOSSIERFASEN.indexOf(verst) ? f : verst));
}

/** Is een "data"-fase rijp genoeg om autonoom over te gaan? Fase-specifiek. */
function faseIsRijp(fase: Dossierfase, dossier: Dossier, rapport: Volledigheidsrapport): boolean {
  // Een kritieke tegenstrijdigheid/onleesbare bron blokkeert altijd.
  if (rapport.aantalKritiek > 0) return false;
  switch (fase) {
    case "intake":
      // Partijen en goed moeten gekend zijn; ontbrekende opzoekingsstukken mogen nog.
      return partijenAanwezig(dossier) && goedAanwezig(dossier);
    case "opzoekingen":
    case "ontwerp":
      // Alle stukken binnen en niets tegenstrijdig.
      return rapport.status === "volledig";
    case "formaliteiten":
      return true; // geen kritiek → de voorbereide formaliteiten mogen door de poort (AUT-O5)
    default:
      return false;
  }
}

function partijenAanwezig(dossier: Dossier): boolean {
  const p = dossier.partijen?.waarde;
  return Array.isArray(p) && p.length > 0;
}

function goedAanwezig(dossier: Dossier): boolean {
  return typeof dossier.goed?.waarde?.adres === "string" && dossier.goed.waarde.adres.trim().length > 0;
}

function bepaalActie(fase: Dossierfase, naar: Dossierfase | null, poort: Poortsoort, klaar: boolean): string {
  if (naar === null) return "Dossier is in de eindfase — geen verdere stap.";
  if (poort === "ambtelijk") return "Klaar voor overdracht aan de notaris voor het verlijden (ambtelijk voorbehoud).";
  if (poort === "notaris") {
    if (fase === "compliance") return "AML/KYC-beoordeling voorleggen aan de notaris (go/no-go).";
    if (fase === "nazicht-validatie") return "Werkdocument ter validatie voorleggen aan de notaris.";
    if (fase === "financiele-afhandeling") return "Doorstorting/afrekening voorbereiden en voorleggen aan de notaris.";
    return "Beslissing voorleggen aan de notaris.";
  }
  return klaar
    ? `Klaar om autonoom over te gaan naar "${naar}".`
    : `Nog niet klaar voor "${naar}" — openstaande punten afwerken.`;
}

/**
 * Leidt de te bewaken termijnen af uit het dossier. Vandaag enkel de canonieke
 * verkooptermijn (verlijden binnen vier maanden na het compromis, de
 * registratietermijn van het verkooprecht). Opschortende voorwaarden en andere
 * termijnen volgen; de opvolgingsmodule (opvolging.ts) bewaakt de rijkere set.
 */
export function bepaalTermijnen(dossier: Dossier, vandaag: string): BeoordeeldeTermijn[] {
  const termijnen: Termijn[] = [];
  const compromisdatum = dossier.compromisdatum?.waarde;
  if (typeof compromisdatum === "string" && /^\d{4}-\d{2}-\d{2}$/.test(compromisdatum)) {
    termijnen.push({
      omschrijving: "Verlijden van de akte binnen vier maanden na het compromis.",
      vervaldatum: vervaldatumNaMaanden(compromisdatum, 4),
    });
  }
  return termijnen.map((t) => ({ ...t, status: termijnStatus(t, vandaag) }));
}
