/**
 * Abnahme für Phase 7 des Umsetzungsplans: Jede Seite muss mit echten
 * Beispieldaten rendern — in beiden Layouts — und die Leerzustände müssen
 * greifen, statt dass eine leere Liste die Seite zerlegt.
 */

import { fireEvent, render, screen, waitFor } from "@testing-library/react"
import { beforeEach, describe, expect, it, vi } from "vitest"

import { DatenAnbieter } from "../daten/DatenKontext"
import { Shell } from "../Shell"
import type { SeitenName } from "../navigation"
import { TITEL } from "../navigation"
import { SeiteFuer } from "./register"
import { beispielApi } from "../tests/beispieldaten"
import { bildschirmbreiteSetzen } from "../tests/aufbau"

const ALLE_SEITEN = Object.keys(TITEL) as SeitenName[]

function zeige(name: SeitenName, id?: string, geheZu: (name: SeitenName, id?: string) => void = () => {}) {
  const api = beispielApi()
  return render(
    <div className="ads-root" data-theme="nacht">
      <DatenAnbieter api={api}>
        <Shell
          route={id === undefined ? { name } : { name, id }}
          geheZu={geheZu}
          tabBeschriftung
        >
          <SeiteFuer
            route={id === undefined ? { name } : { name, id }}
            geheZu={geheZu}
            tabBeschriftung
            setzeTabBeschriftung={() => {}}
            beiAbmeldung={() => {}}
          />
        </Shell>
      </DatenAnbieter>
    </div>,
  )
}

describe("Alle Seiten rendern mit Beispieldaten", () => {
  beforeEach(() => {
    bildschirmbreiteSetzen(390)
  })

  for (const name of ALLE_SEITEN) {
    it(`${name} (${TITEL[name]})`, async () => {
      const id = name === "trip" ? "t1" : name === "fill" ? "f1" : undefined
      const { container } = zeige(name, id)
      // Nach der Erstladung darf kein Ladehinweis mehr stehen.
      await waitFor(() => {
        expect(container.querySelector(".dm-laden")).toBeNull()
      })
      expect(container.textContent?.length ?? 0).toBeGreaterThan(20)
    })
  }

  it("rendert jede Seite auch im Flächenlayout", async () => {
    bildschirmbreiteSetzen(1280)
    for (const name of ALLE_SEITEN) {
      const id = name === "trip" ? "t1" : name === "fill" ? "f1" : undefined
      const { container, unmount } = zeige(name, id)
      await waitFor(() => {
        expect(container.querySelector(".dm-laden")).toBeNull()
      })
      expect(container.querySelector(".dm-seitenleiste")).not.toBeNull()
      unmount()
    }
  })
})

describe("Inhalte kommen wirklich aus den Daten", () => {
  beforeEach(() => {
    bildschirmbreiteSetzen(390)
  })

  it("zeigt Kilometerstand und Reichweite auf der Übersicht", async () => {
    zeige("home")
    await waitFor(() => expect(screen.getByText("48.250")).toBeTruthy())
    expect(screen.getByText("385")).toBeTruthy()
  })

  it("Übersicht: der Serviceblock navigiert, die Kilometerstand-Zeile nicht", async () => {
    // Reproduziert die eigentliche HIG-Vorgabe hinter dem Layout
    // ("differentiate controls from content"), nicht nur das Aussehen:
    // nur der obere Teil der Kachel ist ein Knopf.
    const geheZu = vi.fn()
    const { container } = zeige("home", undefined, geheZu)
    await waitFor(() => expect(screen.getByText("Nächster Service:")).toBeTruthy())

    fireEvent.click(screen.getByText("Nächster Service:"))
    expect(geheZu).toHaveBeenCalledWith("service")

    geheZu.mockClear()
    const zeile = container.querySelector(".dm-servicezeile")
    if (zeile) fireEvent.click(zeile)
    expect(geheZu).not.toHaveBeenCalled()
  })

  it("zeigt eine Gruppe mit unbekanntem Punkt als unbekannt, nicht als sicher", async () => {
    const { container } = zeige("sicherheit")
    await waitFor(() => expect(container.querySelector(".dm-sicherheitsliste")).not.toBeNull())
    // Motorhaube (ok: null) steckt in "tueren_klappen" - die ganze Gruppe
    // gilt damit als unbekannt, nicht als sicher geraten.
    expect(screen.getByText("Türen/Klappen unbekannt")).toBeTruthy()
  })

  it("Sicherheit: Türen und Klappen navigiert zur Detailseite, die anderen Zeilen nicht", async () => {
    const geheZu = vi.fn()
    const { container } = zeige("sicherheit", undefined, geheZu)
    await waitFor(() => expect(container.querySelector(".dm-sicherheitsliste")).not.toBeNull())

    fireEvent.click(screen.getByText("Türen/Klappen unbekannt"))
    expect(geheZu).toHaveBeenCalledWith("tuerenklappen")
  })

  it("Türen und Klappen: zeigt nur die Punkte dieser Gruppe", async () => {
    const { container } = zeige("tuerenklappen")
    await waitFor(() => expect(container.querySelector(".dm-pruefliste")).not.toBeNull())
    expect(screen.getByText("Motorhaube")).toBeTruthy()
    expect(screen.queryByText("Standlicht")).toBeNull()
  })

  it("gruppiert Fahrten nach Jahr", async () => {
    zeige("trips")
    await waitFor(() => expect(screen.getByText("2026")).toBeTruthy())
    expect(screen.getByText("42,5 km")).toBeTruthy()
  })

  it("zeigt bei einer Fahrt ohne Position keine erfundene Route", async () => {
    const { container } = zeige("trip", "t1")
    await waitFor(() => expect(screen.getByText("Keine Route aufgezeichnet")).toBeTruthy())
    expect(container.querySelector(".dm-karte")).toBeNull()
  })

  it("rechnet den Tankvorgang mit mengengewichtetem Preis", async () => {
    zeige("fill", "f1")
    await waitFor(() => expect(screen.getByText("48,70")).toBeTruthy())
    expect(screen.getByText("1,83 €")).toBeTruthy()
  })

  it("bietet beim Eintragen einer Fahrt alle Felder, nicht nur Start/Ende/Art", async () => {
    zeige("trips")
    await waitFor(() => expect(screen.getByText("Fahrt eintragen")).toBeTruthy())
    fireEvent.click(screen.getByText("Fahrt eintragen"))
    expect(screen.getByText("Startort")).toBeTruthy()
    expect(screen.getByText("Zielort")).toBeTruthy()
    expect(screen.getByText("Startkilometer")).toBeTruthy()
    expect(screen.getByText("Endkilometer")).toBeTruthy()
    expect(screen.getByText("Gefahrene Distanz")).toBeTruthy()
  })

  it("lässt eine bestehende Fahrt bearbeiten, vorbelegt mit ihren Werten", async () => {
    zeige("trip", "t1")
    await waitFor(() => expect(screen.getByText("Bearbeiten")).toBeTruthy())
    fireEvent.click(screen.getByText("Bearbeiten"))
    expect(screen.getByText("Fahrt bearbeiten")).toBeTruthy()
    // t1 ist "arbeitsweg" (beispieldaten.ts) - das Auswahlfeld muss das übernehmen,
    // nicht immer bei "privat" neu anfangen.
    const artAuswahl = screen.getByDisplayValue("Arbeitsweg") as HTMLSelectElement
    expect(artAuswahl.value).toBe("arbeitsweg")
  })
})
