// @vitest-environment node
/**
 * Größe und Lage des Hauptfensters.
 *
 * **Der Anlass.** Das Fenster startete bis 0.22.0 immer mit 1180 × 820 an der
 * Systemposition. Wer maximiert arbeitet oder es – wie der Kommentar in
 * `main/fenster.ts` selbst als Anwendungsfall nennt – schmal neben eine
 * Bildschirmlupe oder ein zweites Programm stellt, richtete das bei jedem
 * Start neu ein. Das ist Standard-Erwartung an jede Windows-Anwendung und
 * trifft besonders die Lupen- und Split-Screen-Nutzer, also genau die
 * Zielgruppe des Barrierefreiheitsanspruchs.
 *
 * **Der gefährliche Fall** ist nicht die Größe, sondern die Lage: Ein Fenster,
 * dessen gespeicherte Position auf einem inzwischen abgesteckten Monitor
 * liegt, ginge außerhalb jeder sichtbaren Fläche auf – vorhanden, aber
 * unerreichbar. Und ohne Fenster gibt es keinen Weg, die Einstellung
 * zurückzusetzen. Deshalb ist die Prüfung eine reine Funktion: So lässt sie
 * sich messen, ohne einen zweiten Monitor abzustecken.
 */

import { describe, expect, it } from 'vitest';

import {
  FENSTER_MINDESTBREITE,
  FENSTER_MINDESTHOEHE,
  FENSTER_VORGABE,
  fensterlageBereinigen,
  lageIstErreichbar,
  startlage,
  type Flaeche,
} from '../src/shared/fensterlage';

/** Ein gewöhnlicher Einzelbildschirm. */
const HAUPTSCHIRM: Flaeche = { x: 0, y: 0, width: 1920, height: 1040 };

/** Ein zweiter Schirm links daneben – negative Koordinaten sind normal. */
const ZWEITSCHIRM: Flaeche = { x: -1920, y: 0, width: 1920, height: 1040 };

describe('Gespeicherte Lage bereinigen', () => {
  it('nimmt eine gewöhnliche Lage unverändert', () => {
    expect(fensterlageBereinigen({ breite: 1400, hoehe: 900, x: 100, y: 50 })).toEqual({
      breite: 1400,
      hoehe: 900,
      x: 100,
      y: 50,
    });
  });

  it('merkt sich den maximierten Zustand', () => {
    expect(fensterlageBereinigen({ breite: 1400, hoehe: 900, maximiert: true })).toMatchObject({
      maximiert: true,
    });
  });

  it('verwirft, was keine Lage ist', () => {
    expect(fensterlageBereinigen(null)).toBeNull();
    expect(fensterlageBereinigen('groß')).toBeNull();
    expect(fensterlageBereinigen({})).toBeNull();
    expect(fensterlageBereinigen({ breite: 'viel', hoehe: 900 })).toBeNull();
  });

  it('hebt eine unbedienbar kleine Größe an', () => {
    /* Nach unten gekappt, nicht nach oben: Ein zu großes Fenster schiebt das
       Betriebssystem selbst zurecht, ein zu kleines wäre unbedienbar – und
       niemand könnte es wieder vergrößern, wenn die Ränder fehlen. */
    const lage = fensterlageBereinigen({ breite: 10, hoehe: 10 });

    expect(lage?.breite).toBe(FENSTER_MINDESTBREITE);
    expect(lage?.hoehe).toBe(FENSTER_MINDESTHOEHE);
  });

  it('lässt eine Position ohne Angabe einfach weg', () => {
    const lage = fensterlageBereinigen({ breite: 1400, hoehe: 900 });

    expect(lage).not.toBeNull();
    expect(lage?.x).toBeUndefined();
  });
});

describe('Erreichbarkeit auf den vorhandenen Bildschirmen', () => {
  it('lässt eine Lage mitten auf dem Schirm zu', () => {
    expect(lageIstErreichbar({ breite: 800, hoehe: 600, x: 200, y: 100 }, [HAUPTSCHIRM])).toBe(
      true,
    );
  });

  it('lässt ein Fenster zu, das ein Stück über den Rand ragt', () => {
    /* Alltäglich und gewollt – verlangt wird nur, dass ein greifbarer Teil
       sichtbar bleibt. */
    expect(lageIstErreichbar({ breite: 800, hoehe: 600, x: 1600, y: 900 }, [HAUPTSCHIRM])).toBe(
      true,
    );
  });

  it('weist eine Lage auf einem abgesteckten Monitor ab', () => {
    /* Der eigentliche Schadensfall: Das Fenster ginge auf und bliebe
       unsichtbar – und ohne Fenster ließe sich die Einstellung nicht mehr
       zurücksetzen. */
    const aufZweitschirm = { breite: 800, hoehe: 600, x: -1500, y: 100 };

    expect(lageIstErreichbar(aufZweitschirm, [HAUPTSCHIRM, ZWEITSCHIRM])).toBe(true);
    expect(lageIstErreichbar(aufZweitschirm, [HAUPTSCHIRM])).toBe(false);
  });

  it('weist eine Lage ab, von der nur ein Zipfel sichtbar wäre', () => {
    /* Ein Fenster, das mit zehn Pixeln in den Schirm ragt, lässt sich nicht
       mehr anfassen, um es zurückzuholen. */
    expect(lageIstErreichbar({ breite: 800, hoehe: 600, x: 1910, y: 100 }, [HAUPTSCHIRM])).toBe(
      false,
    );
  });

  it('lässt eine Lage ohne Position immer zu', () => {
    /* Dann entscheidet das Betriebssystem – das ist nie falsch. */
    expect(lageIstErreichbar({ breite: 800, hoehe: 600 }, [])).toBe(true);
  });
});

describe('Startlage', () => {
  it('nimmt die Vorgabe, wenn nichts gespeichert ist', () => {
    expect(startlage(undefined, [HAUPTSCHIRM])).toEqual({ ...FENSTER_VORGABE });
  });

  it('nimmt die Vorgabe, wenn die gespeicherte Lage nicht mehr erreichbar ist', () => {
    const verloren = { breite: 800, hoehe: 600, x: -1500, y: 100 };

    expect(startlage(verloren, [HAUPTSCHIRM])).toEqual({ ...FENSTER_VORGABE });
  });

  it('nimmt die gespeicherte Lage, wenn sie trägt', () => {
    const gespeichert = { breite: 1400, hoehe: 900, x: 100, y: 50, maximiert: true };

    expect(startlage(gespeichert, [HAUPTSCHIRM])).toEqual(gespeichert);
  });

  it('kommt ohne jeden Bildschirm aus', () => {
    /* Sollte nicht vorkommen – aber ein Absturz beim Fensterbau wäre die
       schlechteste Antwort darauf. */
    expect(() => startlage({ breite: 800, hoehe: 600, x: 0, y: 0 }, [])).not.toThrow();
    expect(startlage({ breite: 800, hoehe: 600, x: 0, y: 0 }, [])).toEqual({ ...FENSTER_VORGABE });
  });
});
