// ── Dossier-orkestratie: de "dirigent" ───────────────────────────────────────
// Eén autonome doorloop per dossier: waar de levenscyclus-motor de VOLGENDE
// stap bepaalt, koppelt de orkestratie die stappen tot een volledig plan. Ze
// laat het dossier autonoom zo ver mogelijk vorderen door de "data"-poorten,
// en STOPT (escaleert) bij het eerste haltpunt: een notaris-poort, de
// ambtelijke voorbehoudgrens, een blokkade, of de eindfase. Het plan is puur
// afgeleid en idempotent: dezelfde invoer geeft hetzelfde plan, en hervatten
// vanaf een reeds bereikte fase levert het resterende plan zonder dubbel werk.
//
// De orkestratie MUTEERT niets: ze plant en rapporteert. Het effectief zetten
// van een fase-overgang, het aanroepen van de laag-motoren en het wegschrijven
// van de audit-trail gebeurt door de aanroeper (server/UI), die het plan als
// draaiboek gebruikt. Zo blijft de voorbehoudgrens hard: de motor bereidt voor
// tot aan het verlijden, nooit verder.

import type { Dossier } from "./types";
import type { ExtractieResultaat } from "./perceptie";
import { bepaalVolgendeStapVanaf, type BeoordeeldeTermijn } from "./levenscyclus-motor";
import { faseVanStatus, isEindfase, type Dossierfase } from "./levenscyclus";

/** Waarom de autonome doorloop stopt (het haltpunt). */
export type HaltReden =
  | "notaris-vereist" // een notaris-poort (bv. AML-go, validatie, doorstorting)
  | "ambtelijk" // het verlijden — de voorbehoudgrens, nooit geautomatiseerd
  | "geblokkeerd" // openstaande punten (ontbrekende/tegenstrijdige stukken)
  | "eindfase"; // het dossier is afgewerkt

/** Eén geplande fase-overgang in de doorloop. */
export interface OrkestratieStap {
  vanFase: Dossierfase;
  naarFase: Dossierfase;
  actie: string;
}

/** Het volledige orkestratieplan voor één dossier. */
export interface Orkestratieplan {
  startFase: Dossierfase;
  /** De fasen die Notary.AI autonoom kan voorbereiden/doorlopen, in volgorde. */
  autonomeStappen: OrkestratieStap[];
  /** De fase waar de doorloop halt houdt. */
  haltFase: Dossierfase;
  haltReden: HaltReden;
  /** Mens-leesbare actie bij het haltpunt (wat de notaris of de app moet doen). */
  haltActie: string;
  /** Openstaande punten die de doorloop blokkeren (leeg tenzij haltReden = geblokkeerd). */
  blokkades: string[];
  /** Vereist het haltpunt de notaris (notaris-poort of ambtelijk)? */
  vereistNotaris: boolean;
  /** Bereikt het plan de eindfase zonder tussenkomst? */
  volledigAutonoom: boolean;
  /** De actueel te bewaken termijnen (uit de levenscyclus-motor). */
  termijnen: BeoordeeldeTermijn[];
  /** Append-only auditregels: één regel per geplande stap + het haltpunt. */
  auditRegels: string[];
}

/** Beveiliging tegen een cyclus in de fasetabel: nooit meer stappen dan er fasen zijn. */
const MAX_STAPPEN = 12;

/**
 * Berekent het orkestratieplan voor een dossier tegen referentiedatum `vandaag`
 * (ISO). Begint bij `opties.startFase` (voor hervatting) of anders bij de fase
 * afgeleid uit de dossierstatus, en plant autonome overgangen tot het eerste
 * haltpunt.
 */
export function orkestreer(
  dossier: Dossier,
  vandaag: string,
  opties?: { extractie?: ExtractieResultaat; startFase?: Dossierfase }
): Orkestratieplan {
  const startFase = opties?.startFase ?? faseVanStatus(dossier.status);
  const autonomeStappen: OrkestratieStap[] = [];
  const auditRegels: string[] = [];

  let fase = startFase;
  for (let i = 0; i < MAX_STAPPEN; i++) {
    const stap = bepaalVolgendeStapVanaf(dossier, fase, vandaag, { extractie: opties?.extractie });

    if (stap.aanbevolenFase === null || isEindfase(fase)) {
      auditRegels.push(`halt @ ${fase}: eindfase`);
      return maakPlan(startFase, autonomeStappen, fase, "eindfase", stap.actie, [], false, stap.termijnen, auditRegels);
    }
    if (stap.ambtelijk) {
      auditRegels.push(`halt @ ${fase}: ambtelijk voorbehoud (verlijden)`);
      return maakPlan(startFase, autonomeStappen, fase, "ambtelijk", stap.actie, [], true, stap.termijnen, auditRegels);
    }
    if (stap.vereistNotaris) {
      auditRegels.push(`halt @ ${fase}: notaris vereist`);
      return maakPlan(startFase, autonomeStappen, fase, "notaris-vereist", stap.actie, [], true, stap.termijnen, auditRegels);
    }
    if (!stap.klaarVoorOvergang) {
      auditRegels.push(`halt @ ${fase}: geblokkeerd (${stap.blokkades.length})`);
      return maakPlan(startFase, autonomeStappen, fase, "geblokkeerd", stap.actie, stap.blokkades, false, stap.termijnen, auditRegels);
    }

    // Autonome overgang: plan ze en ga door met de aanbevolen fase.
    autonomeStappen.push({ vanFase: fase, naarFase: stap.aanbevolenFase, actie: stap.actie });
    auditRegels.push(`autonoom: ${fase} → ${stap.aanbevolenFase}`);
    fase = stap.aanbevolenFase;
  }

  // Onbereikbaar bij een acyclische fasetabel; defensieve terugval.
  const laatste = bepaalVolgendeStapVanaf(dossier, fase, vandaag, { extractie: opties?.extractie });
  auditRegels.push(`halt @ ${fase}: stappenlimiet bereikt`);
  return maakPlan(startFase, autonomeStappen, fase, "geblokkeerd", "Stappenlimiet bereikt — controleer de fasetabel.", [], false, laatste.termijnen, auditRegels);
}

function maakPlan(
  startFase: Dossierfase,
  autonomeStappen: OrkestratieStap[],
  haltFase: Dossierfase,
  haltReden: HaltReden,
  haltActie: string,
  blokkades: string[],
  vereistNotaris: boolean,
  termijnen: BeoordeeldeTermijn[],
  auditRegels: string[]
): Orkestratieplan {
  return {
    startFase,
    autonomeStappen,
    haltFase,
    haltReden,
    haltActie,
    blokkades,
    vereistNotaris,
    volledigAutonoom: haltReden === "eindfase",
    termijnen,
    auditRegels,
  };
}

/** Korte samenvatting van een plan voor weergave/log (één regel). */
export function samenvatOrkestratie(plan: Orkestratieplan): string {
  const n = plan.autonomeStappen.length;
  const doorloop = n === 0 ? "geen autonome stap" : `${n} autonome stap${n === 1 ? "" : "pen"} (${plan.startFase} → ${plan.haltFase})`;
  const reden: Record<HaltReden, string> = {
    "notaris-vereist": "wacht op de notaris",
    ambtelijk: "klaar voor het verlijden (ambtelijk)",
    geblokkeerd: `geblokkeerd (${plan.blokkades.length} punt${plan.blokkades.length === 1 ? "" : "en"})`,
    eindfase: "afgewerkt",
  };
  return `${doorloop}; ${reden[plan.haltReden]}.`;
}
