/**
 * Ein einzelner Tankvorgang samt Beleg-Upload. Vorlage: `vFill(id)`.
 *
 * Der Beleg wird als PDF hochgeladen; das Ergebnis kommt **nicht** als
 * Rückgabewert des Dienstaufrufs zurück (pyscript liefert keine), sondern
 * asynchron über die Entität `sensor.audi_dashboard_beleg_ergebnis`.
 * Genau dieses Muster hatte auch das alte Panel.
 */

import { useEffect, useRef, useState } from "react"

import { ActionButton, Pill, Tile } from "@audi-dash/ui"

import { ENTITAETEN } from "../api"
import { useDaten } from "../daten/DatenKontext"
import { datum, datumZeit, de, deOderStrich, eur } from "../format"
import { Leerzustand, Wertzeile, Werteliste } from "./bausteine"

interface BelegErgebnis {
  ok?: boolean
  fehler?: string
  meldung?: string
  tank_id?: string
  [weitere: string]: unknown
}

export function TankDetail({ id }: { id: string | undefined }) {
  const { tankvorgaenge, api } = useDaten()
  const tank = tankvorgaenge.find((t) => t.tank_id === id)

  if (!tank) {
    return (
      <Leerzustand
        titel="Tankvorgang nicht gefunden"
        text="Dieser Eintrag existiert nicht mehr. Vielleicht wurde er gerade gelöscht."
      />
    )
  }

  return (
    <>
      <Tile>
        <span className="ads-eyebrow">{datumZeit(tank.ts)}</span>
        <div className="dm-detail__kopf">
          <div className="dm-detail__zahl">
            {deOderStrich(tank.liters, 2)}
            <span className="dm-detail__einheit">l</span>
          </div>
          <div className="dm-detail__marken">
            {tank.status === "unvollständig" && <Pill>unvollständig</Pill>}
            {tank.source === "beleg" && <Pill>aus Beleg</Pill>}
            {tank.source === "manual" && <Pill>selbst eingetragen</Pill>}
            {tank.source === "auto" && <Pill>automatisch erkannt</Pill>}
          </div>
        </div>
        <Werteliste
          kinder={
            <>
              <Wertzeile
                label="Gesamtbetrag"
                wert={tank.fuel_total_eur != null ? `${eur(tank.fuel_total_eur)} €` : "—"}
              />
              <Wertzeile
                label="Preis je Liter"
                wert={tank.price_per_l != null ? `${eur(tank.price_per_l)} €` : "—"}
                zusatz={
                  tank.list_price_per_l != null
                    ? `Listenpreis ${eur(tank.list_price_per_l)} €`
                    : undefined
                }
              />
              {tank.discount != null && tank.discount > 0 && (
                <Wertzeile label="Ersparnis" wert={`${eur(tank.discount)} €`} />
              )}
              <Wertzeile label="Tankstelle" wert={tank.station_name ?? "—"} zusatz={tank.station_address ?? undefined} />
              <Wertzeile label="Kraftstoff" wert={tank.product_name ?? tank.fuel_type ?? "—"} />
              <Wertzeile
                label="Kilometerstand"
                wert={tank.odometer_km != null ? `${de(tank.odometer_km)} km` : "—"}
              />
              <Wertzeile
                label="Seit der letzten Tankung"
                wert={tank.distance_km != null ? `${de(tank.distance_km)} km` : "—"}
              />
            </>
          }
        />
      </Tile>

      <BelegBereich tankId={tank.tank_id} belegDatei={tank.receipt_file ?? null} belegNr={tank.receipt_no ?? null} zeitpunkt={tank.ts} api={api} />
    </>
  )
}

function BelegBereich({
  tankId,
  belegDatei,
  belegNr,
  zeitpunkt,
  api,
}: {
  tankId: string
  belegDatei: string | null
  belegNr: string | null
  zeitpunkt: string
  api: ReturnType<typeof useDaten>["api"]
}) {
  const dateiwahl = useRef<HTMLInputElement | null>(null)
  const [laeuft, setzeLaeuft] = useState(false)
  const [meldung, setzeMeldung] = useState<{ art: "ok" | "fehler"; text: string } | null>(null)

  // Das Ergebnis kommt asynchron über eine eigene Entität, nicht als Antwort
  // auf den Dienstaufruf. Nach dem Hochladen wird sie deshalb kurz abgefragt.
  const [wartet, setzeWartet] = useState(false)
  useEffect(() => {
    if (!wartet) return
    let abgebrochen = false
    const frist = Date.now() + 20_000

    const abfragen = async () => {
      while (!abgebrochen && Date.now() < frist) {
        await new Promise((weiter) => setTimeout(weiter, 1200))
        try {
          const ergebnis = await api.rest.datenLesen<BelegErgebnis>(ENTITAETEN.belegErgebnis)
          if (abgebrochen) return
          if (ergebnis && ergebnis.tank_id === tankId) {
            setzeWartet(false)
            setzeMeldung(
              ergebnis.ok === false || ergebnis.fehler
                ? { art: "fehler", text: ergebnis.fehler ?? "Der Beleg konnte nicht gelesen werden." }
                : { art: "ok", text: ergebnis.meldung ?? "Beleg übernommen." },
            )
            return
          }
        } catch {
          // Weiterversuchen — ein einzelner Fehlschlag heißt nichts.
        }
      }
      if (!abgebrochen) {
        setzeWartet(false)
        setzeMeldung({
          art: "fehler",
          text: "Der Server hat noch nicht geantwortet. Der Beleg wird trotzdem verarbeitet — die Seite aktualisiert sich, sobald er da ist.",
        })
      }
    }
    void abfragen()
    return () => {
      abgebrochen = true
    }
  }, [wartet, api, tankId])

  const hochladen = async (datei: File) => {
    setzeMeldung(null)
    if (datei.type !== "application/pdf" && !datei.name.toLowerCase().endsWith(".pdf")) {
      setzeMeldung({ art: "fehler", text: "Bitte den Beleg als PDF auswählen." })
      return
    }
    setzeLaeuft(true)
    try {
      const base64 = await alsBase64(datei)
      await api.belegHochladen(base64, datei.name, tankId)
      setzeWartet(true)
    } catch (ursache) {
      setzeMeldung({
        art: "fehler",
        text: ursache instanceof Error ? ursache.message : String(ursache),
      })
    } finally {
      setzeLaeuft(false)
    }
  }

  return (
    <Tile>
      <span className="ads-eyebrow">Beleg</span>
      {belegDatei ? (
        <Werteliste
          kinder={
            <>
              <Wertzeile label="Hinterlegt" wert={belegDatei} />
              <Wertzeile label="Beleg-Nummer" wert={belegNr ?? "—"} />
            </>
          }
        />
      ) : (
        <p className="dm-fussnote">
          Für diese Tankung liegt noch kein Beleg vor. Aus einem Shell-Beleg liest die App Menge,
          Betrag, Tankstelle und Ersparnis selbst aus.
        </p>
      )}

      <input
        ref={dateiwahl}
        type="file"
        accept="application/pdf,.pdf"
        hidden
        onChange={(e) => {
          const datei = e.target.files?.[0]
          if (datei) void hochladen(datei)
          e.target.value = ""
        }}
      />

      {meldung && (
        <p
          className={meldung.art === "fehler" ? "dm-fehler" : "dm-erfolg"}
          role={meldung.art === "fehler" ? "alert" : "status"}
        >
          {meldung.text}
        </p>
      )}

      <div style={{ marginTop: 14 }}>
        <ActionButton onClick={() => dateiwahl.current?.click()} disabled={laeuft || wartet}>
          {laeuft ? "Lade hoch …" : wartet ? "Beleg wird gelesen …" : belegDatei ? "Beleg ersetzen" : "Beleg hochladen"}
        </ActionButton>
      </div>
      <p className="dm-fussnote">
        Der Beleg muss vom {datum(zeitpunkt)} sein — sonst weist der Server ihn ab, damit keine
        fremde Tankung in diesen Eintrag gerät.
      </p>
    </Tile>
  )
}

/** Datei als Base64 ohne den `data:`-Vorspann — so erwartet es das Backend. */
function alsBase64(datei: File): Promise<string> {
  return new Promise((aufloesen, ablehnen) => {
    const leser = new FileReader()
    leser.onload = () => {
      const ergebnis = String(leser.result)
      const komma = ergebnis.indexOf(",")
      aufloesen(komma >= 0 ? ergebnis.slice(komma + 1) : ergebnis)
    }
    leser.onerror = () => ablehnen(new Error("Die Datei konnte nicht gelesen werden."))
    leser.readAsDataURL(datei)
  })
}
