// ── Gedeelde formattering en parsing ─────────────────────────────────────────
// Eén bron van waarheid voor bedrag- en percentageweergave in de hele app.
// Gebruik deze helpers in pagina's, componenten en PDF-generatie — definieer
// ze nooit lokaal opnieuw.

/** Bedrag in euro zonder decimalen: € 350.000 */
export function euro(n: number): string {
  return new Intl.NumberFormat("nl-BE", {
    style: "currency",
    currency: "EUR",
    maximumFractionDigits: 0,
  }).format(n);
}

/**
 * Bedrag als kale cijfers met duizendtalscheiding, zonder muntsymbool: 350.000.
 * Voor sjabloonplaatsen die het muntteken zelf al bevatten ("{{x}} EUR"), zodat
 * er geen dubbele munt verschijnt ("€ 350.000 EUR").
 */
export function bedragCijfers(n: number): string {
  return new Intl.NumberFormat("nl-BE", { maximumFractionDigits: 0 }).format(n);
}

/**
 * Bedrag als kale cijfers, exact: geheel bedrag zonder decimalen ("350.000"),
 * niet-geheel bedrag mét 2 decimalen ("42.555,50"). Gebruik dit voor bedragen
 * die in een akte/compromis terechtkomen: `bedragCijfers` rondt naar hele
 * euro's en zou daar een (juridisch) verkeerde vermelding opleveren.
 */
export function bedragCijfersExact(n: number): string {
  return Number.isInteger(n)
    ? bedragCijfers(n)
    : new Intl.NumberFormat("nl-BE", { minimumFractionDigits: 2, maximumFractionDigits: 2 }).format(n);
}

/**
 * Bedrag met muntsymbool en 2 decimalen, zoals in een akte/compromis bij het
 * bedrag in cijfers naast het bedrag voluit in letters: "€ 1.230.000,00".
 */
export function euroVolledig(n: number): string {
  return new Intl.NumberFormat("nl-BE", {
    style: "currency",
    currency: "EUR",
    minimumFractionDigits: 2,
    maximumFractionDigits: 2,
  }).format(n);
}

/** Percentage met 2 decimalen: "3,50 %" */
export function pct(n: number): string {
  return n.toFixed(2) + " %";
}

/**
 * Parseert gebruikersinvoer naar een getal. Accepteert spaties en punten als
 * duizendtalscheiding en een komma als decimaalteken: "350.000", "350 000",
 * "1.250,50". Ongeldig → 0.
 */
export function parseBedrag(s: string): number {
  return (
    parseFloat(s.replace(/[\s  ]/g, "").replace(/\./g, "").replace(",", ".")) || 0
  );
}

/**
 * Parseert een bedrag uit API-invoer (JSON-body of queryparameter). Een
 * JSON-getal wordt exact overgenomen; een tekst met een punt gevolgd door
 * 1–2 decimalen wordt als decimaalteken gelezen ("250000.5" → 250000,5); al
 * de rest volgt de Belgische invoerconventie van parseBedrag ("350.000" →
 * 350000, "1.250,50" → 1250,5).
 *
 * Achtergrond: parseBedrag is gebouwd voor Belgische UI-invoer en behandelt
 * élke punt als duizendtalscheiding. Een agent die bedrag 250000.5 als
 * JSON-getal stuurde, kreeg via String() → parseBedrag het tienvoudige
 * (2.500.005) in de afrekening — vandaar deze aparte, API-veilige variant.
 */
export function parseBedragInvoer(invoer: unknown): number {
  if (typeof invoer === "number") return Number.isFinite(invoer) ? invoer : 0;
  if (typeof invoer !== "string") return 0;
  const s = invoer.trim();
  if (/^\d+\.\d{1,2}$/.test(s)) return Number(s);
  return parseBedrag(s);
}

// ── Getallen voluit in letters (Nederlands/België) ───────────────────────────
// Voor notariële akten worden bedragen ook voluit geschreven, bv.
// "driehonderdvijftigduizend". Enkel gehele euro's; de notaris leest na.

const EENHEDEN = [
  "nul", "een", "twee", "drie", "vier", "vijf", "zes", "zeven", "acht", "negen",
  "tien", "elf", "twaalf", "dertien", "veertien", "vijftien", "zestien",
  "zeventien", "achttien", "negentien",
];
const TIENTALLEN = [
  "", "", "twintig", "dertig", "veertig", "vijftig", "zestig", "zeventig",
  "tachtig", "negentig",
];

/** Getal 0–99 in letters, met correcte tussen-n en trema (tweeën-, drieën-). */
function onder100(n: number): string {
  if (n < 20) return EENHEDEN[n];
  const tien = TIENTALLEN[Math.floor(n / 10)];
  const eenheid = n % 10;
  if (eenheid === 0) return tien;
  const woord = EENHEDEN[eenheid];
  const verbinding = woord.endsWith("e") ? "ën" : "en";
  return `${woord}${verbinding}${tien}`;
}

/** Getal 0–999 in letters. */
function onder1000(n: number): string {
  if (n < 100) return onder100(n);
  const honderd = Math.floor(n / 100);
  const rest = n % 100;
  const prefix = honderd === 1 ? "honderd" : `${EENHEDEN[honderd]}honderd`;
  return rest === 0 ? prefix : `${prefix}${onder100(rest)}`;
}

/**
 * Geheel getal (0 t.e.m. 999.999.999) voluit in letters, volgens de Belgisch-
 * Nederlandse notariële schrijfwijze (aaneengeschreven, "miljoen" los). Geeft ""
 * terug voor negatieve of te grote getallen.
 */
export function getalInLetters(n: number): string {
  if (!Number.isFinite(n) || n < 0) return "";
  const heel = Math.floor(n);
  if (heel === 0) return "nul";
  if (heel >= 1_000_000_000) return "";

  const miljoen = Math.floor(heel / 1_000_000);
  const duizend = Math.floor((heel % 1_000_000) / 1000);
  const rest = heel % 1000;

  const delen: string[] = [];
  if (miljoen > 0) delen.push(`${miljoen === 1 ? "een" : onder1000(miljoen)} miljoen`);
  if (duizend > 0) delen.push(`${duizend === 1 ? "" : onder1000(duizend)}duizend`);
  if (rest > 0) delen.push(onder1000(rest));

  return delen.join(" ").trim();
}

/** Geheel bedrag voluit in letters, gevolgd door "euro". */
export function bedragInLetters(n: number): string {
  const woorden = getalInLetters(n);
  return woorden ? `${woorden} euro` : "";
}

// ── Datums voluit (Nederlands/België) ────────────────────────────────────────
// Voor notariële akten en onderhandse documenten worden datums voluit
// geschreven, bv. "12 maart 1970" in plaats van "1970-03-12".

const MAANDEN_NL = [
  "januari", "februari", "maart", "april", "mei", "juni",
  "juli", "augustus", "september", "oktober", "november", "december",
];

/**
 * Zet een ISO-datum ("YYYY-MM-DD") om naar de Belgisch-Nederlandse voluit-vorm
 * "12 maart 1970". Een reeds geformatteerde of niet-herkende invoer wordt
 * ongewijzigd teruggegeven, zodat de functie veilig op gemengde invoer kan
 * worden toegepast (we vervormen nooit een waarde die we niet met zekerheid
 * herkennen).
 */
export function formatteerDatumVoluit(datum: string): string {
  const m = /^(\d{4})-(\d{2})-(\d{2})$/.exec(datum.trim());
  if (!m) return datum;
  const jaar = Number(m[1]);
  const maand = Number(m[2]);
  const dag = Number(m[3]);
  if (maand < 1 || maand > 12 || dag < 1 || dag > 31) return datum;
  return `${dag} ${MAANDEN_NL[maand - 1]} ${jaar}`;
}

const MAANDEN_FR = [
  "janvier", "février", "mars", "avril", "mai", "juin",
  "juillet", "août", "septembre", "octobre", "novembre", "décembre",
];

/**
 * Franstalige tegenhanger van formatteerDatumVoluit: "12 mars 1970". Niet-
 * herkende of reeds geformatteerde invoer wordt ongewijzigd teruggegeven.
 */
export function formatteerDatumVoluitFr(datum: string): string {
  const m = /^(\d{4})-(\d{2})-(\d{2})$/.exec(datum.trim());
  if (!m) return datum;
  const maand = Number(m[2]);
  const dag = Number(m[3]);
  if (maand < 1 || maand > 12 || dag < 1 || dag > 31) return datum;
  return `${dag} ${MAANDEN_FR[maand - 1]} ${Number(m[1])}`;
}

/** Validatie van een bedraginvoerveld; null = geldig (of leeg). */
export function valideerBedrag(str: string): string | null {
  if (str === "") return null;
  const n = parseBedrag(str);
  if (n === 0 || isNaN(n))
    return "Voer een geldig bedrag in (bv. 350.000 of 350000)";
  if (n > 50_000_000)
    return "Controleer: dit bedrag lijkt ongewoon hoog (> €50.000.000)";
  return null;
}
