"""CSV-Import für Fahrten, Tankvorgänge und Wartungsplan (Einstellungen ->
"Datensatz laden") - das Gegenstück zum bestehenden, rein clientseitigen
CSV-Export (beide Frontends: der "Datensatz sichern"-Popup baut die Datei
direkt im Browser aus den schon geladenen Daten, ohne Dienstaufruf).

Format identisch zum Export: Semikolon als Trennzeichen, deutsches
Zahlenformat ("," als Dezimaltrennzeichen, optional "." als
Tausendertrennzeichen), UTF-8 mit BOM (wird beim Lesen übersprungen).

ABGLEICH STATT VOLLSTÄNDIGEM ERSATZ (Nutzerentscheidung): eine Zeile mit
bekannter ID aktualisiert NUR die in der CSV enthaltenen Spalten am
bestehenden Datensatz - alles andere (GPS, Route, edited_fields,
Beleg-Verknüpfung, ...) bleibt unangetastet, siehe
`belege.tankvorgang_aktualisieren()`s eigene Begründung. Eine Zeile ohne
oder mit unbekannter ID legt einen neuen Datensatz an - so lässt sich auch
eine von Hand in der Tabelle ergänzte Zeile importieren.

Wartungsplan hat, anders als Fahrten/Tankvorgänge, keine eigene ID - die
Einträge leben als einfache Liste im Fahrzeugprofil und werden bisher nur
über ihren Listenindex adressiert (siehe vSbuch()/Servicebuch() in beiden
Frontends). Der Abgleich läuft dort stattdessen über Datum+Art als
Ersatzschlüssel - eine Zeile, die eines von beidem ändert, wird deshalb
nicht wiedererkannt und legt einen neuen Eintrag an, statt den alten zu
aktualisieren. Für die kleinen, von Hand gepflegten Wartungsplan-Listen
dieses Projekts ist das ein bewusst akzeptierter Kompromiss gegenüber einer
eigens für diesen Zweck eingeführten ID.
"""

from __future__ import annotations

import csv
import io
import logging
from typing import TYPE_CHECKING

from . import belege, fahrterkennung

if TYPE_CHECKING:
    from .koordinator import Koordinator

_LOGGER = logging.getLogger(__name__)


def _de_zahl(text: str | None) -> float | None:
    """"1.234,5" -> 1234.5. None/leer -> None (Spalte nicht gesetzt, nicht
    "auf 0 setzen")."""
    text = (text or "").strip()
    if not text:
        return None
    try:
        return float(text.replace(".", "").replace(",", "."))
    except ValueError:
        return None


def _zeilen(inhalt: str) -> list[dict[str, str]]:
    """CSV-Text (inkl. Kopfzeile, optional mit BOM) als Liste von
    Feldname->Text-Wörterbüchern, in der Reihenfolge der Kopfzeile. Ganz
    leere Zeilen (z. B. eine Leerzeile am Dateiende) werden übersprungen."""
    bereinigt = inhalt.lstrip("﻿")
    zeilen = list(csv.reader(io.StringIO(bereinigt), delimiter=";"))
    if not zeilen:
        return []
    kopf = zeilen[0]
    return [dict(zip(kopf, zeile)) for zeile in zeilen[1:] if any(f.strip() for f in zeile)]


async def fahrten_importieren(k: Koordinator, inhalt: str) -> dict:
    bestehende = {f["trip_id"] for f in await k.ablage.fahrten_lesen()}
    aktualisiert = angelegt = uebersprungen = 0
    for zeile in _zeilen(inhalt):
        trip_id = (zeile.get("ID") or "").strip()
        start = zeile.get("Start") or None
        ende = zeile.get("Ende") or None
        art = zeile.get("Art") or None
        km = _de_zahl(zeile.get("km"))
        if trip_id and trip_id in bestehende:
            await fahrterkennung.aktualisieren(k, {
                "trip_id": trip_id, "ts_start": start, "ts_end": ende,
                "art": art, "distanz": km,
            })
            aktualisiert += 1
        elif start and ende:
            await fahrterkennung.manuell_anlegen(k, {
                "ts_start": start, "ts_end": ende, "art": art, "distanz": km,
            })
            angelegt += 1
        else:
            _LOGGER.warning("CSV-Zeile (Fahrten) ohne Start/Ende übersprungen: %s", zeile)
            uebersprungen += 1
    return {"aktualisiert": aktualisiert, "angelegt": angelegt, "uebersprungen": uebersprungen}


async def tankvorgaenge_importieren(k: Koordinator, inhalt: str) -> dict:
    bestehende = {t["tank_id"] for t in await k.ablage.tankvorgaenge_lesen()}
    aktualisiert = angelegt = uebersprungen = 0
    for zeile in _zeilen(inhalt):
        tank_id = (zeile.get("ID") or "").strip()
        ts = zeile.get("Zeitpunkt") or None
        station = zeile.get("Station") or None
        liter = _de_zahl(zeile.get("Liter"))
        kosten = _de_zahl(zeile.get("Kosten €"))
        if tank_id and tank_id in bestehende:
            daten: dict = {"tank_id": tank_id}
            if ts is not None:
                daten["ts"] = ts
            if liter is not None or kosten is not None:
                daten["liter"] = liter
                daten["kosten"] = kosten
            if station is not None:
                daten["station"] = station
            await belege.tankvorgang_aktualisieren(k, daten)
            aktualisiert += 1
        elif ts and liter is not None and kosten is not None:
            await belege.tankvorgang_manuell(k, {
                "ts": ts, "liter": liter, "kosten": kosten, "station": station,
            })
            angelegt += 1
        else:
            _LOGGER.warning(
                "CSV-Zeile (Tankvorgänge) ohne Zeitpunkt/Liter/Kosten übersprungen: %s", zeile
            )
            uebersprungen += 1
    return {"aktualisiert": aktualisiert, "angelegt": angelegt, "uebersprungen": uebersprungen}


async def wartungsplan_importieren(k: Koordinator, inhalt: str) -> dict:
    profil = await k.ablage.profil_lesen()
    if profil is None:
        return {"aktualisiert": 0, "angelegt": 0, "uebersprungen": 0}
    buch = profil.setdefault("service", {}).setdefault("buch", [])
    aktualisiert = angelegt = uebersprungen = 0
    for zeile in _zeilen(inhalt):
        datum = zeile.get("Datum") or None
        art = zeile.get("Art") or None
        if not datum or not art:
            _LOGGER.warning("CSV-Zeile (Wartungsplan) ohne Datum/Art übersprungen: %s", zeile)
            uebersprungen += 1
            continue
        km = _de_zahl(zeile.get("km"))
        werkstatt = zeile.get("Werkstatt") or None
        kosten = _de_zahl(zeile.get("Kosten €"))
        treffer = next(
            (e for e in buch if e.get("datum") == datum and e.get("art") == art), None
        )
        if treffer is not None:
            if km is not None:
                treffer["km"] = km
            if werkstatt is not None:
                treffer["werkstatt"] = werkstatt
            if kosten is not None:
                treffer["kosten"] = kosten
            aktualisiert += 1
        else:
            buch.append({
                "datum": datum, "km": km or 0, "art": art,
                "werkstatt": werkstatt or "", "kosten": kosten, "arbeiten": "",
            })
            angelegt += 1
    await k.ablage.profil_schreiben(profil)
    await k.profil_veroeffentlichen()
    return {"aktualisiert": aktualisiert, "angelegt": angelegt, "uebersprungen": uebersprungen}


IMPORTIERER = {
    "fahrten": fahrten_importieren,
    "tanken": tankvorgaenge_importieren,
    "service": wartungsplan_importieren,
}


async def importieren(k: Koordinator, art: str, inhalt: str) -> dict:
    funktion = IMPORTIERER.get(art)
    if funktion is None:
        _LOGGER.warning("csv_importieren mit unbekannter Art aufgerufen: %s", art)
        return {"aktualisiert": 0, "angelegt": 0, "uebersprungen": 0}
    ergebnis = await funktion(k, inhalt)
    _LOGGER.info("CSV-Import (%s) abgeschlossen - %s", art, ergebnis)
    return ergebnis
