#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
export_csv.py - Erzeugt CSV aus den von LISP gesammelten Block-Daten.

Aufruf:
    python export_csv.py <export_raw.json> <data_dir> <output.csv>

Argumente:
    export_raw.json - JSON-Datei mit allen INSERT-Entities aus der Zeichnung
    data_dir        - Pfad zum data/-Verzeichnis (mit json/ Unterordner)
    output.csv      - Ziel-CSV-Datei
"""

import json
import sys
import os
import uuid


def load_json(path):
    with open(path, "r", encoding="utf-8") as f:
        return json.load(f)


def build_lookup(boegen, weichen):
    """Erzeugt ein Dict: SivasNr (als String) -> (typ, eintrag)"""
    lookup = {}
    for b in boegen:
        key = str(b["Sivasnr"])
        lookup[key] = ("bogen", b)
    for w in weichen:
        key = str(w["Sivasnr"])
        lookup[key] = ("weiche", w)
    return lookup


def generate_shape_id():
    return "shape_" + str(uuid.uuid4())


def classify_weiche(eintrag):
    """Bestimmt den Weichen-Subtyp fuer die Omniflo Sum Zaehlung."""
    wt = eintrag.get("WeichenTyp", "")
    profil = eintrag.get("ProfilTyp", "")
    if "WEICHENKOERPER" in profil.upper():
        return "weichenkoerper"
    if wt == "Einzelweiche":
        return "einzelweiche"
    if wt == "Doppelweiche":
        return "doppelweiche"
    if wt == "Dreiwegeweiche":
        return "dreiwegeweiche"
    if wt == "Deltaweiche" or "DELTA" in profil.upper():
        return "deltaweiche"
    if wt == "Dreifachweiche":
        return "deltaweiche"
    if wt == "Sternweiche" or "STAR" in profil.upper():
        return "sternweiche"
    return "einzelweiche"


def build_bogen_merkmale(block, eintrag):
    """Merkmale-JSON fuer einen Omniflo Bogen."""
    return {
        "Länge in Meter": "0",
        "Kurvenwinkel": eintrag.get("KurvenWinkel", 0),
        "Radius": eintrag.get("Radius", 0),
        "Höhe": "2000",
        "Drehung": block.get("rotation", 0.0),
        "SivasNummer": str(eintrag.get("Sivasnr", ""))
    }


def build_weiche_merkmale(block, eintrag):
    """Merkmale-JSON fuer eine Omniflo Weiche."""
    wt = eintrag.get("WeichenTyp", "Einzelweiche")
    return {
        "Länge in Meter links": None,
        "Länge in Meter rechts": None,
        "Länge in Meter gerade": None,
        "Weichentyp": wt,
        "Richtung": str(eintrag.get("KurvenRichtung", "")),
        "Weichenwinkel": eintrag.get("KurvenWinkel", 0),
        "Höhe": "2000",
        "Drehung": block.get("rotation", 0.0),
        "Antrieb Kurve": eintrag.get("SivasnrTEF") is not None,
        "SivasNummer": str(eintrag.get("Sivasnr", ""))
    }


def build_gerade_merkmale(block):
    """Merkmale-JSON fuer eine Omniflo Gerade (AP110)."""
    return {
        "Anzahl der Separatoren": "0",
        "Länge in Meter": "2",
        "Winkel": "0",
        "Anzahl der Scanner": 0,
        "Höhe oben": "2000",
        "Höhe unten": "2000",
        "Drehung": block.get("rotation", 0.0),
        "SivasNummer": ""
    }


def build_kreisel_merkmale(block):
    """Merkmale-JSON fuer einen ILS Kreisel."""
    return {
        "Abstand (Kreiselachse A - Kreiselachse) in Meter": "3",
        "Anzahl der Separatoren": "2",
        "Kreiselart": "Standard",
        "Anzahl der Scanner": "0",
        "Anzahl der Rampen": "0",
        "Höhe in m": "2",
        "Drehrichtung": "UZS",
        "Drehung": block.get("rotation", 0.0)
    }


# --- Bekannte Blocknamen fuer nicht-Omniflo Elemente ---
KREISEL_BLOCKS = {"AN8", "SP8"}

VARIO_BLOCKS = {
    "AUS_Element_links", "EIN_Element_links",
    "Staustrecke_SP_1000_mm", "Staustrecke_Separator_SP_300_mm",
    "Vario_Spannstation_SP_500mm", "Vario_Motorstation_SP_500mm",
}

# Koordinatensystem-Bloecke (ignorieren)
SKIP_BLOCKS = {"K1", "K2", "K3", "K4", "KS_EIN", "KS_AUS"}


def process_blocks(blocks, lookup):
    """
    Verarbeitet alle Bloecke und erzeugt:
    - items: Liste der CSV-Einzelzeilen
    - counters: Zaehler fuer Summierungszeilen
    """
    items = []
    counters = {
        # Omniflo Sum
        "anzahl_boegen": 0,
        "anzahl_weichenkoerper": 0,
        "anzahl_einzelweichen": 0,
        "anzahl_deltaweichen": 0,
        "anzahl_doppel_dreiwegeweichen": 0,
        "anzahl_sternweichen": 0,
        "gesamtlaenge_ap110": 0.0,
        "gesamtlaenge_ap60": 0.0,
        # ILS Automation
        "anzahl_kreisel": 0,
        "anzahl_kreisel_pinband": 0,
        "sep_kreisel_pin": 0,
        "sep_kreisel_ohne_pin": 0,
        "anzahl_verbindungskreisel": 0,
        "laengen_kreisel": 0.0,
        "anzahl_weichen_ils": 0,
        "anzahl_eckraeder": 0,
        "anzahl_gefaellestrecken": 0,
        "anzahl_variofoerderer": 0,
        "anzahl_streckengruppen": 0,
        "laengen_gefaellestrecken": 0.0,
        "anzahl_motoren_vario": 0,
        "laengen_variofoerderer": 0.0,
        "anzahl_etf": 0,
        "laengen_etf": 0.0,
        "anzahl_separatoren": 0,
        "anzahl_scanner": 0,
        "anzahl_btbeladung": 0,
        "anzahl_abwurfstationen": 0,
    }

    elem_nr = 0
    bogen_count = 0
    weiche_count = {}
    gerade_count = 0
    kreisel_count = 0

    for block in blocks:
        bname = block.get("block_name", "")

        # Koordinatensystem-Bloecke ueberspringen
        if bname in SKIP_BLOCKS:
            continue

        # Omniflo Bogen oder Weiche?
        if bname in lookup:
            typ, eintrag = lookup[bname]
            elem_nr += 1
            shape_id = generate_shape_id()

            if typ == "bogen":
                bogen_count += 1
                items.append({
                    "nr": elem_nr,
                    "teileart": "Omniflo Kurve",
                    "teileid": shape_id,
                    "bezeichnung": f"OFBogen :{bogen_count}",
                    "anzahl": 1,
                    "merkmale": build_bogen_merkmale(block, eintrag)
                })
                counters["anzahl_boegen"] += 1

            elif typ == "weiche":
                subtyp = classify_weiche(eintrag)
                wt = eintrag.get("WeichenTyp", "Einzelweiche")
                weiche_count[wt] = weiche_count.get(wt, 0) + 1

                items.append({
                    "nr": elem_nr,
                    "teileart": "Omniflo Weiche",
                    "teileid": shape_id,
                    "bezeichnung": f"OFWeiche :{weiche_count[wt]}",
                    "anzahl": 1,
                    "merkmale": build_weiche_merkmale(block, eintrag)
                })

                if subtyp == "einzelweiche":
                    counters["anzahl_einzelweichen"] += 1
                elif subtyp == "doppelweiche" or subtyp == "dreiwegeweiche":
                    counters["anzahl_doppel_dreiwegeweichen"] += 1
                elif subtyp == "deltaweiche":
                    counters["anzahl_deltaweichen"] += 1
                elif subtyp == "sternweiche":
                    counters["anzahl_sternweichen"] += 1
                elif subtyp == "weichenkoerper":
                    counters["anzahl_weichenkoerper"] += 1

            continue

        # Omniflo Gerade (AP110)
        if "AP110" in bname.upper() or "AP_110" in bname.upper():
            elem_nr += 1
            gerade_count += 1
            items.append({
                "nr": elem_nr,
                "teileart": "Omniflo Gerade",
                "teileid": generate_shape_id(),
                "bezeichnung": f"OFGerade :{gerade_count}",
                "anzahl": 1,
                "merkmale": build_gerade_merkmale(block)
            })
            counters["gesamtlaenge_ap110"] += 2000.0
            continue

        # ILS Kreisel
        if bname in KREISEL_BLOCKS:
            elem_nr += 1
            kreisel_count += 1
            items.append({
                "nr": elem_nr,
                "teileart": "ILS 2.0 Kreisel",
                "teileid": generate_shape_id(),
                "bezeichnung": f"Kreisel :{kreisel_count}",
                "anzahl": 1,
                "merkmale": build_kreisel_merkmale(block)
            })
            counters["anzahl_kreisel"] += 1
            counters["sep_kreisel_ohne_pin"] += 2
            counters["laengen_kreisel"] += 3.0
            counters["anzahl_separatoren"] += 2
            if counters["anzahl_streckengruppen"] == 0:
                counters["anzahl_streckengruppen"] = 1
            continue

        # VarioFoerderer-Bloecke
        is_vario = False
        for vb in VARIO_BLOCKS:
            if vb in bname:
                is_vario = True
                break
        if is_vario:
            counters["anzahl_variofoerderer"] += 1
            continue

    return items, counters


def build_ils_automation_row(elem_nr, counters):
    """Erzeugt die ILS 2.0 Automation Summierungszeile."""
    merkmale = {
        "Anzahl Kreisel": counters["anzahl_kreisel"],
        "Anzahl Kreisel mit Pinband": counters["anzahl_kreisel_pinband"],
        "Anzahl aller Separatoren in Kreisel mit PIN": counters["sep_kreisel_pin"],
        "Anzahl aller Separatoren in Kreisel ohne PIN": counters["sep_kreisel_ohne_pin"],
        "Anzahl Verbindungskreisel": counters["anzahl_verbindungskreisel"],
        "Längen aller Kreisel": counters["laengen_kreisel"],
        "Anzahl der Weichen": counters["anzahl_weichen_ils"],
        "Anzahl der Eckräder": counters["anzahl_eckraeder"],
        "Anzahl der einzelnen Gefällestrecken": counters["anzahl_gefaellestrecken"],
        "Anzahl der einzelnen Varioförderer": counters["anzahl_variofoerderer"],
        "Anzahl der Streckengruppen": counters["anzahl_streckengruppen"],
        "Längen aller Gefällestrecken": counters["laengen_gefaellestrecken"],
        "Anzahl der Motoren Varioförderer": counters["anzahl_motoren_vario"],
        "Längen aller Varioförderer": counters["laengen_variofoerderer"],
        "Anzahl ETFs": counters["anzahl_etf"],
        "Längen aller ETFs": counters["laengen_etf"],
        "Anzahl aller Separatoren": counters["anzahl_separatoren"],
        "Anzahl aller Scanner": counters["anzahl_scanner"],
        "Anzahl aller BTBeladung": counters["anzahl_btbeladung"],
        "Anzahl aller Abwurfstationen": counters["anzahl_abwurfstationen"],
    }
    return {
        "nr": elem_nr,
        "teileart": "ILS 2.0 Automation",
        "teileid": "autogenerated_ils_automation_json",
        "bezeichnung": "Automation ILS structgen",
        "anzahl": 1,
        "merkmale": merkmale,
    }


def build_omniflo_sum_row(elem_nr, counters):
    """Erzeugt die Omniflo Sum Summierungszeile."""
    merkmale = {
        "Anzahl Bögen": counters["anzahl_boegen"],
        "Anzahl Weichengrundkörper": counters["anzahl_weichenkoerper"],
        "Anzahl Einwegweichen": counters["anzahl_einzelweichen"],
        "Anzahl Deltaweichen": counters["anzahl_deltaweichen"],
        "Anzahl Doppelweichen und Dreiwegeweichen": counters["anzahl_doppel_dreiwegeweichen"],
        "Anzahl Sternweichen": counters["anzahl_sternweichen"],
        "Gesamtlänge AP110": counters["gesamtlaenge_ap110"],
        "Gesamtlänge AP60": counters["gesamtlaenge_ap60"],
    }
    return {
        "nr": elem_nr,
        "teileart": "Omniflo Sum",
        "teileid": "autogenerated_of_json",
        "bezeichnung": "Omniflo sum",
        "anzahl": 1,
        "merkmale": merkmale,
    }


def format_csv_line(item):
    """Formatiert eine CSV-Zeile im geforderten Format."""
    merkmale_json = json.dumps(item["merkmale"], ensure_ascii=False)
    return '{nr};"{teileart}";"{teileid}";"{bezeichnung}";{anzahl};{merkmale}'.format(
        nr=item["nr"],
        teileart=item["teileart"],
        teileid=item["teileid"],
        bezeichnung=item["bezeichnung"],
        anzahl=item["anzahl"],
        merkmale=merkmale_json,
    )


def main():
    if len(sys.argv) < 4:
        print("Aufruf: python export_csv.py <export_raw.json> <data_dir> <output.csv>")
        sys.exit(1)

    raw_json_path = sys.argv[1]
    data_dir = sys.argv[2]
    output_csv = sys.argv[3]

    # Daten laden
    blocks = load_json(raw_json_path)
    boegen_path = os.path.join(data_dir, "json", "omniflo_boegen.json")
    weichen_path = os.path.join(data_dir, "json", "omniflo_weichen.json")

    boegen = load_json(boegen_path) if os.path.exists(boegen_path) else []
    weichen = load_json(weichen_path) if os.path.exists(weichen_path) else []

    lookup = build_lookup(boegen, weichen)

    print(f"[export_csv] {len(blocks)} Bloecke geladen, "
          f"{len(boegen)} Boegen, {len(weichen)} Weichen im Katalog.")

    # Bloecke verarbeiten
    items, counters = process_blocks(blocks, lookup)

    # Summierungszeilen anhaengen
    next_nr = (items[-1]["nr"] + 1) if items else 1

    ils_row = build_ils_automation_row(next_nr, counters)
    items.append(ils_row)

    of_row = build_omniflo_sum_row(next_nr + 1, counters)
    items.append(of_row)

    # CSV schreiben
    header = "Elementnummer;TeileArt;TeileId;Bezeichnung;Anzahl;Merkmale"
    with open(output_csv, "w", encoding="utf-8") as f:
        f.write(header + "\n")
        for item in items:
            f.write(format_csv_line(item) + "\n")

    print(f"[export_csv] CSV geschrieben: {output_csv} ({len(items)} Zeilen)")


if __name__ == "__main__":
    main()
