/**
 * Die Anzeigegröße der Anwendung – reine Logik, ohne Electron.
 *
 * **Warum Zoom und nicht nur Schriftgröße.** Eine reine Schriftvergrößerung
 * lässt Bilder unberührt. Der Katalog führt siebzehn Prüfzeichen, bei denen das
 * Bild die Antwort ist – ein Beschusszeichen, ein PTB-Kreis. Wer
 * größere Schrift braucht, braucht diese Zeichen erst recht größer. Der Zoom
 * skaliert alles gemeinsam, und das Layout dieser Anwendung ist darauf
 * ausgelegt: Es fließt um, statt zu brechen.
 *
 * **Warum feste Stufen.** Stufenlos wäre schwerer zu treffen und schwerer
 * anzusagen. Die Leiter deckt den Bereich ab, den WCAG 1.4.4 verlangt
 * (200 Prozent), reicht bis zu dem, an dem WCAG 1.4.10 misst (400 Prozent),
 * und lässt darunter Luft für kleinere Anzeigen.
 *
 * **Warum sie bis 400 Prozent geht.** 1.4.10 (Reflow) ist an einer Messung
 * festgemacht: 400 Prozent Vergrößerung auf einem 1280 Pixel breiten Fenster,
 * also 320 CSS-Pixel Inhaltsbreite. Endete die Leiter bei 200 Prozent, ließe
 * sich dieser Fall mit Bordmitteln gar nicht herstellen – das Kriterium wäre
 * nicht erfüllt, sondern nur unprüfbar. Die drei oberen Stufen (250, 300,
 * 400) sind dieselben, die auch Chromium anbietet; wer sie aus dem Browser
 * kennt, findet keine fremde Skala vor.
 */

/** Die wählbaren Anzeigegrößen in Prozent. */
export const ANZEIGEGROESSEN = Object.freeze([
  80, 90, 100, 110, 125, 150, 175, 200, 250, 300, 400,
] as const);

export type Anzeigegroesse = (typeof ANZEIGEGROESSEN)[number];

/** Vorgabe: unverändert. */
export const ANZEIGEGROESSE_STANDARD = 100;

/**
 * Bringt einen beliebigen Wert auf eine gültige Stufe.
 *
 * Nicht die nächstgelegene, sondern die nächstkleinere gültige Stufe: Wer
 * einen Wert zwischen zwei Stufen gespeichert hat – etwa aus einer früheren
 * Fassung –, soll nicht plötzlich größer sehen als vorher.
 */
export function anzeigegroesseBereinigen(wert: unknown): number {
  if (typeof wert !== 'number' || !Number.isFinite(wert)) {
    return ANZEIGEGROESSE_STANDARD;
  }
  const kleinste = ANZEIGEGROESSEN[0];
  const groesste = ANZEIGEGROESSEN[ANZEIGEGROESSEN.length - 1] ?? ANZEIGEGROESSE_STANDARD;
  if (wert <= kleinste) {
    return kleinste;
  }
  if (wert >= groesste) {
    return groesste;
  }
  return [...ANZEIGEGROESSEN].reverse().find((stufe) => stufe <= wert) ?? ANZEIGEGROESSE_STANDARD;
}

/** Eine Stufe größer; an der obersten Stufe bleibt es dabei. */
export function groesser(aktuell: number): number {
  const jetzt = anzeigegroesseBereinigen(aktuell);
  return ANZEIGEGROESSEN.find((stufe) => stufe > jetzt) ?? jetzt;
}

/** Eine Stufe kleiner; an der untersten Stufe bleibt es dabei. */
export function kleiner(aktuell: number): number {
  const jetzt = anzeigegroesseBereinigen(aktuell);
  return [...ANZEIGEGROESSEN].reverse().find((stufe) => stufe < jetzt) ?? jetzt;
}

export function istGroesstmoeglich(wert: number): boolean {
  return anzeigegroesseBereinigen(wert) === ANZEIGEGROESSEN[ANZEIGEGROESSEN.length - 1];
}

export function istKleinstmoeglich(wert: number): boolean {
  return anzeigegroesseBereinigen(wert) === ANZEIGEGROESSEN[0];
}

/**
 * Chromiums Zoomfaktor zur Prozentangabe.
 *
 * `setZoomFactor(1.5)` entspricht 150 Prozent – die Umrechnung ist trivial
 * und steht trotzdem hier, damit die Prozentzahl die eine Wahrheit bleibt
 * und niemand an zwei Stellen mit 1,5 gegen 150 hantiert.
 */
export function zoomfaktor(prozent: number): number {
  return anzeigegroesseBereinigen(prozent) / 100;
}

/** „125 Prozent" – für Ansagen und Beschriftungen. */
export function anzeigegroesseText(prozent: number): string {
  return `${String(anzeigegroesseBereinigen(prozent))} Prozent`;
}
