/**
 * Größe und Lage des Hauptfensters – reine Logik, ohne Electron.
 *
 * **Wozu.** Das Fenster startete bis 0.22.0 immer mit derselben Größe an der
 * Systemposition. Wer maximiert arbeitet oder es schmal neben eine
 * Bildschirmlupe oder ein zweites Programm stellt, richtete das bei jedem
 * Start neu ein — und das sind gerade die Nutzer, für die diese Anwendung
 * gebaut ist.
 *
 * **Warum die Prüfung hier liegt und nicht bei der Fenstererzeugung.** An ihr
 * hängt der einzige gefährliche Fall: eine gespeicherte Lage auf einem
 * Bildschirm, den es nicht mehr gibt. Das Fenster ginge dann außerhalb jeder
 * sichtbaren Fläche auf — vorhanden, aber unerreichbar, und ohne Fenster gibt
 * es auch keinen Weg, die Einstellung zurückzusetzen. Als reine Funktion
 * lässt sich das prüfen, ohne einen zweiten Monitor abzustecken.
 */

/** Fenstergröße und -lage, wie sie gespeichert wird. */
export interface Fensterlage {
  readonly breite: number;
  readonly hoehe: number;
  readonly x?: number;
  readonly y?: number;
  readonly maximiert?: boolean;
}

/** Ein Rechteck einer verfügbaren Bildschirmfläche. */
export interface Flaeche {
  readonly x: number;
  readonly y: number;
  readonly width: number;
  readonly height: number;
}

/** Vorgabe, wenn nichts gespeichert ist oder das Gespeicherte nicht taugt. */
export const FENSTER_VORGABE = Object.freeze({ breite: 1180, hoehe: 820 });

/** Untergrenzen; dieselben wie `minWidth`/`minHeight` am Fenster. */
export const FENSTER_MINDESTBREITE = 360;
export const FENSTER_MINDESTHOEHE = 560;

/** So viel vom Fenster muss auf einer Fläche liegen, damit es greifbar ist. */
const SICHTBAR_MINDESTENS = 80;

function zahl(wert: unknown): number | null {
  return typeof wert === 'number' && Number.isFinite(wert) ? Math.round(wert) : null;
}

/**
 * Nimmt eine gespeicherte Lage entgegen und gibt zurück, was davon taugt.
 *
 * `null` heißt: nichts Brauchbares, es gilt die Vorgabe.
 */
export function fensterlageBereinigen(wert: unknown): Fensterlage | null {
  if (typeof wert !== 'object' || wert === null) {
    return null;
  }
  const roh = wert as Record<string, unknown>;

  const breite = zahl(roh['breite']);
  const hoehe = zahl(roh['hoehe']);
  if (breite === null || hoehe === null) {
    return null;
  }

  const x = zahl(roh['x']);
  const y = zahl(roh['y']);

  return {
    /* Nach unten gekappt, nicht nach oben: Ein zu großes Fenster schiebt das
       Betriebssystem selbst zurecht, ein zu kleines wäre unbedienbar. */
    breite: Math.max(FENSTER_MINDESTBREITE, breite),
    hoehe: Math.max(FENSTER_MINDESTHOEHE, hoehe),
    ...(x === null ? {} : { x }),
    ...(y === null ? {} : { y }),
    ...(roh['maximiert'] === true ? { maximiert: true } : {}),
  };
}

/**
 * Ob die gespeicherte Lage auf einer der vorhandenen Flächen liegt.
 *
 * Verlangt wird kein vollständiges Enthaltensein: Ein Fenster, das ein Stück
 * über den Rand ragt, ist gewollt und alltäglich. Verlangt wird, dass ein
 * greifbarer Teil sichtbar bleibt — sonst ließe es sich nicht einmal mehr
 * anfassen, um es zurückzuholen.
 */
export function lageIstErreichbar(lage: Fensterlage, flaechen: readonly Flaeche[]): boolean {
  const { x, y } = lage;
  if (x === undefined || y === undefined) {
    /* Ohne Position entscheidet das Betriebssystem – das ist immer gültig. */
    return true;
  }

  return flaechen.some((flaeche) => {
    const ueberlappungX =
      Math.min(x + lage.breite, flaeche.x + flaeche.width) - Math.max(x, flaeche.x);
    const ueberlappungY =
      Math.min(y + lage.hoehe, flaeche.y + flaeche.height) - Math.max(y, flaeche.y);
    return ueberlappungX >= SICHTBAR_MINDESTENS && ueberlappungY >= SICHTBAR_MINDESTENS;
  });
}

/**
 * Die Lage, mit der das Fenster aufgehen soll.
 *
 * Fällt auf die Vorgabe zurück, wenn nichts gespeichert ist oder die
 * gespeicherte Lage auf keiner vorhandenen Fläche mehr liegt.
 */
export function startlage(gespeichert: unknown, flaechen: readonly Flaeche[]): Fensterlage {
  const lage = fensterlageBereinigen(gespeichert);
  if (lage === null || !lageIstErreichbar(lage, flaechen)) {
    return { ...FENSTER_VORGABE };
  }
  return lage;
}
