#!/usr/bin/env python3
"""Baut die Phase-0-Vorschau: Feature-Sicht + Einheiten → aufklappbares HTML.

Aufruf: baue-vorschau.py <features.md> <projekt-wurzel> <ausgabe.html> <einheiten.md ...>

Der konkrete Code je Einheit wird live aus der Quelle extrahiert (Anker: Pfad::Symbol) —
Artefakte enthalten nie Code-Kopien.
"""
import html
import json
import re
import sys
from pathlib import Path


def einheiten_parsen(pfade) -> dict:
    out = {}
    aktuelle = None
    modus = None
    for pfad in pfade:
        for zeile in Path(pfad).read_text(encoding="utf-8").splitlines():
            if zeile.startswith("## ") and "::" in zeile:
                aktuelle = {"id": zeile[3:].strip(), "beschreibung": "", "input": "",
                            "output": "", "entscheidungen": [], "kanten": [], "anker": []}
                out[aktuelle["id"]] = aktuelle
                modus = None
            elif aktuelle is None:
                continue
            elif zeile.startswith("beschreibung:"):
                aktuelle["beschreibung"] = zeile.split(":", 1)[1].strip(); modus = "beschreibung"
            elif zeile.startswith("input:"):
                aktuelle["input"] = zeile.split(":", 1)[1].strip(); modus = "input"
            elif zeile.startswith("output:"):
                aktuelle["output"] = zeile.split(":", 1)[1].strip(); modus = "output"
            elif zeile.startswith("anker:"):
                aktuelle["anker"].append(zeile.split(":", 1)[1].strip())
            elif zeile.strip() in ("entscheidungen:", "fakten:"):
                modus = "punkte"
            elif zeile.strip() == "kanten:":
                modus = "kanten"
            elif modus == "punkte" and (m := re.match(r'\s+beleg:\s*"(.*)"', zeile)):
                pass  # Belege prüft pruefe.py; die Vorschau zeigt echten Code statt Zitaten
            elif modus == "punkte" and zeile.startswith("- "):
                aktuelle["entscheidungen"].append(zeile[2:].strip())
            elif modus == "punkte" and zeile.startswith("  ") and aktuelle["entscheidungen"]:
                aktuelle["entscheidungen"][-1] += " " + zeile.strip()
            elif modus == "kanten" and (m := re.match(r"- ([\wäöü-]+):\s*(\S+)", zeile)):
                aktuelle["kanten"].append({"typ": m.group(1), "ziel": m.group(2)})
            elif modus in ("beschreibung", "input", "output") and zeile.startswith("  "):
                aktuelle[modus] += " " + zeile.strip()
    return out


def features_parsen(pfad) -> list:
    bereiche = []
    bereich = feature = None
    for zeile in Path(pfad).read_text(encoding="utf-8").splitlines():
        if zeile.startswith("# Bereich:"):
            bereich = {"name": zeile.split(":", 1)[1].strip(), "beschreibung": "", "features": []}
            bereiche.append(bereich); feature = None
        elif zeile.startswith("## Feature:"):
            titel = zeile[11:].strip()
            flag = "kern" if "[kern]" in titel else "rand"
            feature = {"titel": re.sub(r"\s*\[(kern|rand)\]", "", titel).strip(),
                       "flag": flag, "beschreibung": "", "teilfeatures": []}
            bereich["features"].append(feature)
        elif zeile.startswith("### ") and feature is not None:
            feature["teilfeatures"].append({"titel": zeile[4:].strip(), "einheiten": []})
        elif zeile.startswith("einheiten:") and feature and feature["teilfeatures"]:
            feature["teilfeatures"][-1]["einheiten"] = \
                [t.strip() for t in zeile.split(":", 1)[1].split(",") if t.strip()]
        elif zeile.startswith("beschreibung:"):
            ziel = feature if feature is not None else bereich
            if ziel is not None:
                ziel["beschreibung"] = zeile.split(":", 1)[1].strip()
    return bereiche


def code_extrahieren(wurzel: Path, eid: str) -> str:
    """Quellcode eines Ankers (pfad::symbol): def/class-Block per Einrückung."""
    if "::" not in eid:
        return ""
    datei, symbol = eid.split("::", 1)
    p = wurzel / datei
    if not p.is_file():
        return ""
    zeilen = p.read_text(encoding="utf-8").splitlines()
    start = None
    for i, z in enumerate(zeilen):
        if re.match(rf"(\s*)(?:async\s+)?(?:def|class)\s+{re.escape(symbol)}\b", z):
            start = i
            break
        if re.match(rf"{re.escape(symbol)}\s*[:=]", z):  # Modul-Konstante
            start = i
            ende = i + 1
            while ende < len(zeilen) and (zeilen[ende].startswith((" ", "\t", ")", "]", "}"))
                                          or not zeilen[ende].strip()):
                ende += 1
            return "\n".join(zeilen[start:ende]).rstrip()
    if start is None:
        return ""
    einzug = len(zeilen[start]) - len(zeilen[start].lstrip())
    ende = start + 1
    while ende < len(zeilen):
        z = zeilen[ende]
        if z.strip() and (len(z) - len(z.lstrip())) <= einzug:
            break
        ende += 1
    return "\n".join(zeilen[start:ende]).rstrip()


def main():
    features_pfad, wurzel, ausgabe = sys.argv[1], Path(sys.argv[2]), sys.argv[3]
    einheiten = einheiten_parsen(sys.argv[4:])
    bereiche = features_parsen(features_pfad)
    code = {}
    for e in einheiten.values():
        for eid in [e["id"], *e["anker"]]:
            code[e["id"]] = code.get(e["id"]) or code_extrahieren(wurzel, eid)
    daten = {"bereiche": bereiche, "einheiten": einheiten, "code": code}
    tpl = Path(__file__).with_name("vorschau-template.html").read_text(encoding="utf-8")
    Path(ausgabe).write_text(tpl.replace("/*DATEN*/", json.dumps(daten, ensure_ascii=False)),
                             encoding="utf-8")
    n_feat = sum(len(b["features"]) for b in bereiche)
    print(f"{ausgabe}: {len(bereiche)} Bereiche, {n_feat} Features, {len(einheiten)} Einheiten")


if __name__ == "__main__":
    main()
