// ── Woord-diff ───────────────────────────────────────────────────────────────
// Pure, dependency-vrije woord-diff (LCS) voor het markeren van wijzigingen in
// een wijzigingsvoorstel t.o.v. de bestaande clausule/model (ValiderenTab).
// Geen woordgrenzen negeren: whitespace blijft als eigen token behouden zodat
// de opgebouwde tekst exact reconstrueerbaar is uit de segmenten.

export type DiffSegmentSoort = "gelijk" | "verwijderd" | "toegevoegd";

export interface DiffSegment {
  soort: DiffSegmentSoort;
  tekst: string;
}

function tokeniseer(tekst: string): string[] {
  return tekst.split(/(\s+)/).filter((t) => t !== "");
}

/**
 * Vergelijkt `oud` met `nieuw` op woordniveau en geeft een lijst segmenten
 * terug (gelijk/verwijderd/toegevoegd) op basis van de langste gemeenschappelijke
 * deelrij (LCS) van de tokens.
 */
export function woordDiff(oud: string, nieuw: string): DiffSegment[] {
  const a = tokeniseer(oud);
  const b = tokeniseer(nieuw);
  const n = a.length;
  const m = b.length;

  const dp: number[][] = Array.from({ length: n + 1 }, () => new Array(m + 1).fill(0));
  for (let i = n - 1; i >= 0; i--) {
    for (let j = m - 1; j >= 0; j--) {
      dp[i][j] = a[i] === b[j] ? dp[i + 1][j + 1] + 1 : Math.max(dp[i + 1][j], dp[i][j + 1]);
    }
  }

  const segmenten: DiffSegment[] = [];
  const voegToe = (soort: DiffSegmentSoort, tekst: string) => {
    const laatste = segmenten[segmenten.length - 1];
    if (laatste && laatste.soort === soort) laatste.tekst += tekst;
    else segmenten.push({ soort, tekst });
  };

  let i = 0;
  let j = 0;
  while (i < n && j < m) {
    if (a[i] === b[j]) {
      voegToe("gelijk", a[i]);
      i += 1;
      j += 1;
    } else if (dp[i + 1][j] >= dp[i][j + 1]) {
      voegToe("verwijderd", a[i]);
      i += 1;
    } else {
      voegToe("toegevoegd", b[j]);
      j += 1;
    }
  }
  while (i < n) {
    voegToe("verwijderd", a[i]);
    i += 1;
  }
  while (j < m) {
    voegToe("toegevoegd", b[j]);
    j += 1;
  }
  return segmenten;
}
