#!/usr/bin/env python3
"""
FUN-Jugendreisen · Zustiegsplanung Import
==========================================
Erzeugt data.json + index.html aus dem CSV-Export.

Verwendung:
    python import_csv.py                        # Standard
    python import_csv.py --input meine.csv      # Andere CSV
    python import_csv.py --output /pfad/zu/     # Ausgabeverzeichnis
    python import_csv.py --richtung ALLE        # HIN + RÜC
"""

import re
import argparse, json, sys, csv, gzip, base64
from pathlib import Path
from datetime import datetime

# ── Datenbank-Konfiguration ──────────────────────────────────────────
# Credentials werden aus db_connect.inc gelesen.
# Erwartet wird eine PHP-Datei mit Variablen im Format:
#   $db_host = 'localhost';
#   $db_name = 'fun_db';
#   $db_user = 'fun_user';
#   $db_pass = 'geheim';
#   $db_port = 3306;       (optional, Default: 3306)

def fetch_destinations_from_db(output_path: Path) -> bool:
    """
    Ruft fetch_destinations.php per subprocess auf.
    PHP erledigt die DB-Verbindung und schreibt destinationen.csv.
    """
    import subprocess

    script_dir = Path(__file__).parent
    php_script = script_dir / 'fetch_destinations.php'

    if not php_script.exists():
        print(f"  ⚠  fetch_destinations.php nicht gefunden: {php_script}")
        return False

    try:
        result = subprocess.run(
            ['php', str(php_script)],
            capture_output=True, text=True, timeout=30
        )
    except FileNotFoundError:
        print("  ⚠  PHP nicht gefunden — ist PHP im PATH?")
        return False
    except subprocess.TimeoutExpired:
        print("  ⚠  PHP-Script Timeout (>30s)")
        return False

    if result.returncode != 0:
        msg = (result.stderr or result.stdout or 'unbekannter Fehler').strip()
        print(f"  ⚠  fetch_destinations.php: {msg}")
        return False

    count = result.stdout.strip()
    print(f"  Destinationen: {count} Einträge aus DB → {output_path.name}")
    return True



# ── Eingebettetes HTML-Gerüst ────────────────────────────────────────
_TEMPLATE_B64 = """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"""

def get_template() -> str:
    return gzip.decompress(base64.b64decode(_TEMPLATE_B64)).decode("utf-8")

# ── Konfiguration ────────────────────────────────────────────────────
REISE_ICONS = {
    "Spanien":  "\U0001f1ea\U0001f1f8",
    "Italien":  "\U0001f1ee\U0001f1f9",
    "Kroatien": "\U0001f1ed\U0001f1f7",
    "London":   "\U0001f1ec\U0001f1e7",
    "Paris":    "\U0001f5fc",
}
COL_MAP = {
    "Abfahrtsdatum": "datum",  "Abfahrtsort": "ort",
    "Abfahrtszeit":  "zeit",   "Fahrzeug":    "bus",
    "Name":          "name",   "Vorname":     "vorname",
    "Reise":         "reise",  "PlanungsArt": "richtung",
    "Vorgang_Fun":   "vorgang",
    "Agenturnummer": "agentur",
}

# ── CSV lesen ────────────────────────────────────────────────────────
def read_csv(path):
    for enc in ("utf-8-sig", "latin-1"):
        try:
            text = path.read_text(encoding=enc); break
        except UnicodeDecodeError: continue
    else:
        sys.exit(f"FEHLER: Datei nicht lesbar: {path}")
    sep = ";" if text.split("\n")[0].count(";") > text.split("\n")[0].count(",") else ","
    return [{k.strip(): (v or "").strip() for k, v in row.items() if k}
            for row in csv.DictReader(text.splitlines(), delimiter=sep)]

def normalize(rows):
    if not rows: return []
    resolved = {}
    for col in rows[0]:
        for substr, key in COL_MAP.items():
            if substr in col: resolved[col] = key; break
    return [{resolved.get(k, k): v for k, v in r.items()} for r in rows]

def filter_rows(rows, richtung):
    return [r for r in rows
            if r.get("datum","") and not r.get("datum","").startswith("-----")
            and (richtung == "ALLE" or r.get("richtung","") == richtung)]

# ── Datenstruktur ────────────────────────────────────────────────────

# ── Destination-Mapping laden ────────────────────────────────────────
def load_destinations(path) -> dict:
    """
    Liest destinationen.csv (Export der Query):
      SELECT vorgang, Destination FROM tb_buchungsliste GROUP BY vorgang, Destination
    Gibt dict zurück: { vorgang_str: destination_str }
    """
    if not path.exists():
        return {}
    for enc in ("utf-8-sig", "latin-1"):
        try:
            text = path.read_text(encoding=enc); break
        except UnicodeDecodeError: continue
    else:
        return {}
    line1 = text.split("\n")[0]
    sep = ";" if line1.count(";") > line1.count(",") else ","
    result = {}
    for row in csv.DictReader(text.splitlines(), delimiter=sep):
        cleaned = {k.strip().lower(): (v or "").strip() for k, v in row.items() if k}
        # Spalten erkennen: vorgang + destination
        v_col = next((k for k in cleaned if "vorgang" in k), None)
        d_col = next((k for k in cleaned if "dest" in k), None)
        if v_col and d_col and cleaned.get(v_col):
            result[cleaned[v_col].strip()] = cleaned.get(d_col, "").strip()
    return result


def load_teilnehmer(path) -> dict:
    """
    Liest teilnehmer.csv.
    Gibt dict zurück: { (vorgang, name_lower, vorname_lower): tel_str }
    """
    if not path.exists():
        return {}
    for enc in ("utf-8-sig", "latin-1"):
        try:
            text = path.read_text(encoding=enc); break
        except UnicodeDecodeError:
            continue
    else:
        return {}
    line1 = text.split("\n")[0]
    sep   = ";" if line1.count(";") > line1.count(",") else ","
    result = {}
    for row in csv.DictReader(text.splitlines(), delimiter=sep):
        cleaned = {k.strip().lower(): (v or "").strip() for k, v in row.items() if k}
        vg      = cleaned.get("vorgang", "").strip()
        name    = cleaned.get("name",    "").strip().lower()
        vorname = cleaned.get("vorname", "").strip().lower()
        tel     = cleaned.get("handynummer", "").strip()
        if vg and name and tel:
            result[(vg, name, vorname)] = tel
    return result

def build(rows, destinations=None, telefon=None):
    if destinations is None: destinations = {}
    if telefon is None:     telefon      = {}
    raw = {}
    richtung_map = {}   # datum → set("HIN", "RÜC")
    bus_richtung  = {}  # (datum,reise,bus) → {'HIN':n, 'RÜC':n}
    for r in rows:
        d, reise, bus = r.get("datum",""), r.get("reise",""), r.get("bus","")
        name, vname   = r.get("name",""), r.get("vorname","")
        # Robust: erst gemappten Key "richtung" prüfen,
        # Fallback: beliebigen Key der "planungsart" enthält (case-insensitiv)
        _richtung_val = r.get("richtung", "")
        if not _richtung_val:
            for _k, _v in r.items():
                if "planungsart" in _k.lower():
                    _richtung_val = _v
                    break
        richtung      = _richtung_val.strip().upper()
        is_ruec       = richtung in ("RÜC", "RUC")

        if is_ruec:
            dest = destinations.get(r.get("vorgang","").strip(), "")
            ort  = dest if dest else "Unbekannt"
            zeit = ort
            richtung_map.setdefault(d, set()).add("RÜC")
        else:
            ort  = r.get("ort","")
            zeit = r.get("zeit","")
            richtung_map.setdefault(d, set()).add("HIN")

        if not all([d, reise, bus, ort, name]): continue
        (raw.setdefault(d,{}).setdefault(reise,{}).setdefault(bus,{})
            .setdefault(ort,{"zeit":zeit,"pax":[]})["pax"].append(
                {"n":name,"v":vname,
                 "d":destinations.get(r.get("vorgang","").strip(),""),
                 "rl":r.get("agentur","").strip()=="0992",
                 "tel":telefon.get((r.get("vorgang","").strip(),
                       name.lower(),vname.lower()),"")}))
        # Richtung pro Bus merken
        _bk = (d,reise,bus)
        _bc = bus_richtung.setdefault(_bk, {'HIN':0,'RÜC':0})
        _bc['RÜC' if is_ruec else 'HIN'] += 1
    result = {}
    for datum in sorted(raw, key=_parse_date):
        result[datum] = {}
        for reise in raw[datum]:
            result[datum][reise] = {}
            for bus in sorted(raw[datum][reise]):
                stops = sorted(
                    [{"ort":ort,"zeit":info["zeit"],
                      "pax":sorted(info["pax"],key=lambda p:p["n"])}
                     for ort,info in raw[datum][reise][bus].items()],
                    key=lambda s: s["zeit"])
                icon = next((v for k,v in REISE_ICONS.items() if k in reise), "\U0001f68c")
                _bc  = bus_richtung.get((datum,reise,bus), {'HIN':1,'RÜC':0})
                # Mehrheitsprinzip: Richtung mit mehr Passagieren gewinnt
                _bdir = 'HIN' if _bc['HIN'] >= _bc['RÜC'] else 'RÜC'
                result[datum][reise][bus] = {
                    "stops": stops, "total": sum(len(s["pax"]) for s in stops),
                    "icon": icon, "richtung": [_bdir]}
    # richtung_map: sets → lists für JSON-Serialisierung
    richtung_json = {d: list(v) for d, v in richtung_map.items()}
    return result, richtung_json

def _parse_date(d):
    try: return datetime.strptime(d, "%d.%m.%Y")
    except: return datetime.min

# ── Statistik ────────────────────────────────────────────────────────
def print_stats(data):
    buses = sum(sum(len(b) for b in r.values()) for r in data.values())
    pax   = sum(bd["total"] for r in data.values() for b in r.values() for bd in b.values())
    print(f"\n  Abfahrtsdaten : {len(data)}")
    print(f"  Busse gesamt  : {buses}")
    print(f"  Fahrgäste (HIN): {pax}")
    print(f"  {'─'*40}")
    for datum, reisen in data.items():
        for reise, bd in reisen.items():
            p = sum(b["total"] for b in bd.values())
            print(f"  {datum}  {len(bd):2} Busse  {p:4} Pax  {reise[:32]}")
    print()

# ── Main ─────────────────────────────────────────────────────────────
def main():
    p = argparse.ArgumentParser()
    p.add_argument("--input",    default="Export-Web-Freiplatz.csv")
    p.add_argument("--output",   default=".")
    p.add_argument("--richtung", default="ALLE", choices=["HIN","ALLE"])
    args = p.parse_args()

    csv_path = Path(args.input)
    out_dir  = Path(args.output)
    if not csv_path.exists():
        sys.exit(f"FEHLER: CSV nicht gefunden: {csv_path}")
    out_dir.mkdir(parents=True, exist_ok=True)

    print(f"\n  CSV  : {csv_path}  ({csv_path.stat().st_size/1024:.0f} KB)")
    rows = filter_rows(normalize(read_csv(csv_path)), args.richtung)
    print(f"  Zeilen: {len(rows)}  (Richtung: {args.richtung})")
    # Schritt 1: Destinationen aus Datenbank holen
    dest_file = csv_path.parent / "destinationen.csv"
    db_ok = fetch_destinations_from_db(dest_file)
    if not db_ok:
        # Fallback: vorhandene destinationen.csv verwenden
        if dest_file.exists():
            print(f"  Destinationen: verwende vorhandene {dest_file.name}")
        else:
            print(f"  Destinationen: keine verfügbar — Zustiegsliste ohne Destination-Info")

    # Schritt 2: Destinationen einlesen und verknüpfen
    destinations = load_destinations(dest_file) if dest_file.exists() else {}
    if destinations:
        print(f"  Destinationen: {len(destinations)} Vorgänge verknüpft")
    # Schritt 3: Telefonnummern aus teilnehmer.csv laden
    teil_file = csv_path.parent / "teilnehmer.csv"
    telefon   = load_teilnehmer(teil_file)
    if telefon:
        print(f"  Telefonnummern: {len(telefon)} Einträge")
    else:
        print(f"  Telefonnummern: teilnehmer.csv nicht gefunden oder leer")

    data, richtung = build(rows, destinations, telefon)
    print_stats(data)

    # data.json schreiben — wird von api.php?action=data live ausgeliefert
    data_json = {"data": data, "richtung": richtung}
    json_str  = json.dumps(data_json, ensure_ascii=False, separators=(",",":"))
    data_file = out_dir / "data.json"
    data_file.write_text(json_str, encoding="utf-8")
    print(f"  data.json: {data_file}  ({len(json_str.encode())/1024:.0f} KB)")

    # index.html aus Template (ohne eingebettete Daten)
    html      = get_template()
    html_file = out_dir / "index.html"
    html_file.write_text(html, encoding="utf-8")
    print(f"  index.html: {html_file}  ({len(html.encode())/1024:.0f} KB)")
    print(f"\n  → index.html + data.json auf den Server laden.\n")

if __name__ == "__main__":
    main()
