import { useCallback, useEffect, useMemo, useState } from "react"

import { DataMetricApi, zugangLesen } from "./api"
import { DatenAnbieter, useDaten } from "./daten/DatenKontext"
import { startklarMelden } from "./daten/ota"
import { Shell } from "./Shell"
import type { Route, SeitenName } from "./navigation"
import { useTabBeschriftung, useTheme } from "./theme"
import { Einrichtung } from "./screens/Einrichtung"
import { Hinweisleiste } from "./screens/Hinweisleiste"
import { SeiteFuer } from "./screens/register"
import { zugangMerken } from "./screens/zugang"

import "./stile/rahmen.css"
import "./stile/screens.css"

type Startzustand = "pruefen" | "einrichten" | "bereit"

/**
 * Wurzel der App. Entscheidet zuerst, ob Zugangsdaten vorliegen — ohne sie
 * gibt es nichts anzuzeigen außer der Ersteinrichtung. Danach hängt alles
 * unter dem Datenkontext.
 */
export function App() {
  const [theme] = useTheme()
  const [start, setzeStart] = useState<Startzustand>("pruefen")

  // Genau eine Instanz für die Lebensdauer der App: sie hält die
  // WebSocket-Verbindung und die Warteschlange.
  const api = useMemo(() => new DataMetricApi(), [])

  useEffect(() => {
    void zugangLesen().then(async (zugang) => {
      // Adresse für Bild-URLs merken, bevor der erste Screen rendert.
      if (zugang) await zugangMerken()
      setzeStart(zugang ? "bereit" : "einrichten")
    })
  }, [])

  return (
    <div className="ads-root dm-wurzel" data-theme={theme}>
      {start === "pruefen" && <div className="dm-laden">Einen Moment …</div>}
      {start === "einrichten" && <Einrichtung fertig={() => setzeStart("bereit")} />}
      {start === "bereit" && (
        <DatenAnbieter api={api}>
          <AngemeldeteApp beiAbmeldung={() => setzeStart("einrichten")} />
        </DatenAnbieter>
      )}
    </div>
  )
}

function AngemeldeteApp({ beiAbmeldung }: { beiAbmeldung: () => void }) {
  const [route, setzeRoute] = useState<Route>({ name: "home" })
  const [tabBeschriftung, setzeTabBeschriftung] = useTabBeschriftung()
  const daten = useDaten()

  const geheZu = useCallback((name: SeitenName, id?: string) => {
    setzeRoute(id === undefined ? { name } : { name, id })
    document.querySelector(".dm-inhalt")?.scrollTo({ top: 0 })
  }, [])

  // Ein abgelaufener oder zurückgezogener Token führt zurück in die
  // Ersteinrichtung statt in eine endlose Fehlerschleife.
  useEffect(() => {
    if (daten.verbindung === "nicht_angemeldet") beiAbmeldung()
  }, [daten.verbindung, beiAbmeldung])

  // Meldet dem OTA-Plugin, dass diese Fassung hochgekommen ist (siehe
  // daten/ota.ts). Bewusst hier und nicht in main.tsx: erst wenn diese
  // Komponente rendert, hat React tatsächlich etwas auf den Schirm gebracht.
  // Ein Absturz vor diesem Punkt bleibt unbestätigt, und das Plugin rollt
  // nach appReadyTimeout von selbst auf das vorherige Bündel zurück.
  useEffect(() => {
    void startklarMelden()
  }, [])

  return (
    <Shell
      route={route}
      geheZu={geheZu}
      tabBeschriftung={tabBeschriftung}
      hinweis={
        <Hinweisleiste
          verbindung={daten.verbindung}
          warteschlange={daten.warteschlange}
          versionsstand={daten.versionsstand}
        />
      }
    >
      <SeiteFuer
        route={route}
        geheZu={geheZu}
        tabBeschriftung={tabBeschriftung}
        setzeTabBeschriftung={setzeTabBeschriftung}
        beiAbmeldung={beiAbmeldung}
      />
    </Shell>
  )
}
