"""Generiert ein Mermaid-Datenlineage-Diagramm aus den Metadaten.

Zeigt den Datenfluss: Externe Quellen → Power Query → Tabellen → Beziehungen.
Sprachabhängig (de/en).
"""
from __future__ import annotations

from core.label_i18n import table_type_label
from core.models import ReportMetadata

_T: dict[str, dict[str, str]] = {
    "de": {
        "empty": "*Keine Datenlineage-Informationen verfügbar "
                 "(keine Tabellen oder Datenquellen extrahiert).*",
        "sources": "Quellen",
        "model": "Modell",
        "unknown": "Unbekannt",
    },
    "en": {
        "empty": "*No data lineage information available "
                 "(no tables or data sources extracted).*",
        "sources": "Sources",
        "model": "Model",
        "unknown": "Unknown",
    },
}


def generate_lineage_diagram(metadata: ReportMetadata, language: str = "de") -> str:
    """Erzeugt ein Mermaid-Flowchart-Diagramm der Datenlineage.

    Struktur:
      Externe Quelle --> Power Query --> Tabelle
      Tabelle -- Beziehung --> Tabelle
    """
    t = _T.get(language, _T["de"])

    # Sammle eindeutige externe Quellen aus Power Queries
    sources: dict[str, str] = {}  # id → label
    pq_to_table: list[tuple[str, str, str]] = []  # (source_id, pq_name, table)

    for pq in metadata.power_queries:
        source_label = pq.source or t["unknown"]
        source_id = _safe_id("src_" + source_label)
        if source_id not in sources:
            sources[source_id] = source_label

        pq_to_table.append((source_id, pq.name, pq.target_table))

    # Sammle Tabellen (nur nicht-versteckte)
    table_ids: dict[str, str] = {}
    for tbl in metadata.tables:
        if not tbl.is_hidden:
            tid = _safe_id("tbl_" + tbl.name)
            table_ids[tbl.name] = tid

    # Ohne Knoten kein Diagramm erzeugen: Ein leeres `flowchart` wird von
    # vielen Mermaid-Renderern (insb. älteren Versionen wie v8) als Parse-Fehler
    # behandelt und gar nicht angezeigt. Stattdessen einen Hinweistext liefern.
    if not sources and not table_ids:
        return t["empty"]

    lines: list[str] = ["```mermaid", "flowchart LR"]

    # Subgraph: Externe Quellen
    if sources:
        lines.append(f"    subgraph {t['sources']}")
        for sid, label in sources.items():
            lines.append(f"        {sid}[(\"{_esc(label)}\")]")
        lines.append("    end")

    # Subgraph: Tabellen
    if table_ids:
        lines.append(f"    subgraph {t['model']}")
        for tname, tid in table_ids.items():
            tinfo = next((tt for tt in metadata.tables if tt.name == tname), None)
            suffix = ""
            if tinfo and tinfo.table_type:
                suffix = f"<br/>({table_type_label(tinfo.table_type, language)})"
            lines.append(f"        {tid}[\"{_esc(tname)}{suffix}\"]")
        lines.append("    end")

    # Kanten: Quelle → Tabelle (über Power Query)
    seen_edges: set[str] = set()
    for source_id, _pq_name, target_table in pq_to_table:
        target_id = table_ids.get(target_table)
        if target_id:
            edge_key = f"{source_id}->{target_id}"
            if edge_key not in seen_edges:
                lines.append(f"    {source_id} --> {target_id}")
                seen_edges.add(edge_key)

    # Kanten: Beziehungen zwischen Tabellen
    for rel in metadata.relationships:
        from_id = table_ids.get(rel.from_table)
        to_id = table_ids.get(rel.to_table)
        if from_id and to_id:
            card = _short_cardinality(rel.cardinality)
            edge_key = f"{from_id}--{to_id}"
            if edge_key not in seen_edges:
                lines.append(f"    {from_id} -- \"{card}\" --> {to_id}")
                seen_edges.add(edge_key)

    lines.append("```")
    return "\n".join(lines)


def _safe_id(text: str, max_len: int = 40) -> str:
    """Erzeugt eine sichere Mermaid-Knoten-ID mit begrenzter Länge.

    Lange IDs (z.B. aus Fabric Connection Strings) werden gekürzt und
    mit einem Hash-Suffix versehen um Eindeutigkeit zu gewährleisten.
    """
    raw = "".join(c if c.isalnum() else "_" for c in text)
    if len(raw) <= max_len:
        return raw
    # Kürzen + 8-Zeichen-Hash für Eindeutigkeit
    import hashlib
    suffix = hashlib.md5(text.encode()).hexdigest()[:8]
    return raw[: max_len - 9] + "_" + suffix


def _esc(text: str) -> str:
    """Escaped Sonderzeichen für Mermaid-Labels."""
    result = text.replace('"', "'").replace("\n", " ")
    # Auf 50 Zeichen kürzen (sicher für Mermaid-Rendering)
    if len(result) > 50:
        result = result[:47] + "..."
    # Trailing-Punkt/Sonderzeichen entfernen (verwirrt Mermaid-Parser)
    result = result.rstrip(". ")
    return result


def _short_cardinality(card: str) -> str:
    """Kürzt Kardinalitätsbezeichnungen."""
    mapping = {
        "OneToMany": "1:n",
        "ManyToOne": "n:1",
        "OneToOne": "1:1",
        "ManyToMany": "n:m",
    }
    return mapping.get(card, card)
