"""Generator für die Dataflow-Dokumentation (Gen1 & Gen2).

Analog zu :mod:`core.workspace_doc_generator` und
:mod:`core.report_document_builder`: enthält die eingebaute Standard-Vorlage
für ein eigenständiges Dataflow-Dokument sowie die Funktionen, die aus einem
:class:`~core.models.DataflowInfo` das Platzhalter-Wörterbuch und die
Markdown-Tabellen erzeugen.

Die Vorlage wird – falls noch nicht vorhanden – als Datei neben der Anwendung
erzeugt und danach als Standard verwendet, sodass sie (wie die Berichts- und
Workspace-Vorlagen) vom Benutzer angepasst werden kann.
"""
from __future__ import annotations

from core.models import DataflowEntityInfo, DataflowInfo, RefreshScheduleInfo
from core.template_renderer import TemplateRenderer
from core.workspace_doc_generator import _escape_cell, ensure_template, load_template

# Dateiname der Standard-Vorlage (liegt neben der EXE / im Projektstamm)
DATAFLOW_TEMPLATE_FILENAME = "WorkspaceDataflowvorlage.md"

__all__ = [
    "DATAFLOW_TEMPLATE_FILENAME",
    "DEFAULT_DATAFLOW_TEMPLATE",
    "ensure_template",
    "load_template",
    "build_entities_table",
    "build_attributes_table",
    "build_queries_section",
    "build_mashup_section",
    "build_refresh_plan",
    "build_service_hint",
    "build_dataflow_values",
    "render_dataflow",
]


# ---------------------------------------------------------------------------
# Eingebaute Standard-Vorlage (deckungsgleich mit
# PowerBI_Dataflow_Dokumentationsvorlage.md im Projektstamm)
# ---------------------------------------------------------------------------

DEFAULT_DATAFLOW_TEMPLATE = """# Power BI / Fabric Dataflow-Dokumentation

> **Hinweis:** Diese Dokumentation ist verpflichtend für alle Produktiv-Dataflows
> (Gen1 & Gen2).
> Nicht relevante Kapitel können leer bleiben, dürfen jedoch nicht entfernt werden.
> Automatisch befüllte Felder stammen aus dem Power BI / Fabric Service; mit
> _„Manuell zu ergänzen"_ markierte Felder sind fachlich zu vervollständigen.

---

## 1. Metadaten

| Feld | Wert |
|-----|------|
| Dataflow-Name | {{DF_Name}} |
| Beschreibung | {{DF_Beschreibung}} |
| Generation | {{DF_Generation}} |
| Dataflow-ID | {{DF_ID}} |
| Web-URL | {{DF_WebUrl}} |
| Erstellt / konfiguriert von | {{DF_ConfiguredBy}} |
| Zuletzt geändert | {{DF_ModifiedTime}} |
| Fachbereich | {{DF_Fachbereich}} |
| Konzerndomäne | {{DF_Konzerndomaene}} |
| Aktuelle Version | 1.0 |
| Status | Produktiv |
| Letzte Aktualisierung | {{DF_ExportDatum}} |

---

## 2. Ansprechpartner & Verantwortlichkeiten

| Rolle | Name / Team | Kontakt |
|-----|-------------|--------|
| Fachlicher Owner | {{KONTAKT_BusinessOwner}} | {{KONTAKT_BusinessOwnerMail}} |
| Technischer Owner | {{KONTAKT_TechOwner}} | {{KONTAKT_TechOwnerMail}} |
| Data Steward | {{KONTAKT_DataSteward}} | {{KONTAKT_DataStewardMail}} |
| Betrieb / Support | {{KONTAKT_Betrieb}} | {{KONTAKT_BetriebMail}} |

---

## 3. Business-Ziel & fachlicher Kontext

### 3.1 Zielsetzung
{{DF_Zielsetzung}}

### 3.2 Fachlicher Anwendungsfall
{{DF_Anwendungsfall}}

### 3.3 Konsumenten (Semantic Models / Berichte / weitere Dataflows)
{{DF_Konsumenten}}

---

## 4. Entitäten & Struktur

### 4.1 Übersicht der Entitäten

{{DF_EntitaetenTabelle}}

### 4.2 Attribute je Entität

{{DF_AttributeTabelle}}

---

## 5. Datenquellen & Datenherkunft

### 5.1 Übersicht der Datenquellen

{{DF_DatenquellenTabelle}}

### 5.2 Detailbeschreibung je Datenquelle
{{DF_DatenquellenDetail}}

---

## 6. Power Query (Datentransformation)

{{DF_ServiceHinweis}}

### 6.1 Transformationslogik je Entität (M)

{{DF_Queries}}

### 6.2 Vollständiges Mashup-/M-Dokument

{{DF_MashupDokument}}

### 6.3 Parameter & Funktionen
{{DF_ParameterHinweis}}

### 6.4 Fehlerbehandlung & Datenqualität

- Umgang mit NULL-Werten: {{DF_NullHandling}}
- Fehlerhafte Zeilen: {{DF_ErrorHandling}}
- Datenvalidierungsregeln: {{DF_Validierungsregeln}}

### 6.5 Performance-Hinweise

- Query Folding aktiv: {{DF_QueryFolding}}
- Bekannte Performance-Engpässe: {{DF_PerformanceHinweise}}
- Optimierungsmaßnahmen: {{DF_Optimierungen}}

---

## 7. Betrieb & Wartung

### 7.1 Aktualisierung (Refresh)

{{DF_RefreshPlan}}

### 7.2 Monitoring & Fehlerbehandlung
{{DF_Monitoring}}

### 7.3 Bekannte Probleme / Technische Schulden
{{DF_BekannteProbleme}}

---

## 8. Sicherheit & Berechtigungen

### 8.1 Zugriff & Freigaben
{{DF_Zugriffe}}

### 8.2 Sensitivity Labels
{{DF_Labels}}

### 8.3 Risiken & Einschränkungen
{{DF_Risiken}}

---

## 9. Versionierung & Änderungsverlauf

### 9.1 Repository / Ablage
{{DF_Repository}}

### 9.2 Änderungsprotokoll

| Version | Datum | Änderung | Typ (fachlich/technisch) | Autor |
|-------|-------|---------|--------------------------|-------|
| 1.0 | {{DF_ExportDatum}} | Automatische Erst-Dokumentation | technisch | Auto-Dokumentation |

---

## 10. Freigabe & Review

| Rolle | Name | Datum | Kommentar |
|-----|------|-------|----------|
| Fachlich | {{REVIEW_FachName}} | {{REVIEW_FachDatum}} | {{REVIEW_FachKommentar}} |
| Technisch | {{REVIEW_TechName}} | {{REVIEW_TechDatum}} | {{REVIEW_TechKommentar}} |

---

## 11. Anhänge & Referenzen
- Übergeordnete Workspace-Dokumentation
- Architekturdiagramme
- Regulatorische Nachweise (separat)
"""


# ---------------------------------------------------------------------------
# Lokalisierungs-Hilfen
# ---------------------------------------------------------------------------

def _t(language: str, de: str, en: str) -> str:
    """Wählt den Text je nach Sprache (Default: Deutsch)."""
    return en if (language or "de").lower().startswith("en") else de


def _manual_hint(language: str) -> str:
    return _t(language, "_Manuell zu ergänzen_", "_To be completed_")


def _none(language: str) -> str:
    return _t(language, "–", "–")


# ---------------------------------------------------------------------------
# Tabellen-/Abschnitts-Generierung
# ---------------------------------------------------------------------------

def build_entities_table(
    entities: list[DataflowEntityInfo], language: str = "de"
) -> str:
    """Baut die Übersichtstabelle der Entitäten."""
    if not entities:
        return _t(
            language,
            "_Keine Entitäten verfügbar._",
            "_No entities available._",
        )
    header = _t(
        language,
        "| Entität | Attribute | Berechnet | Beschreibung |",
        "| Entity | Attributes | Computed | Description |",
    )
    yes = _t(language, "Ja", "Yes")
    no = _t(language, "Nein", "No")
    lines = [header, "|---|---|---|---|"]
    for ent in entities:
        lines.append(
            f"| {_escape_cell(ent.name)} | {len(ent.attributes)} | "
            f"{yes if ent.is_computed else no} | "
            f"{_escape_cell(ent.description) or '–'} |"
        )
    return "\n".join(lines)


def build_attributes_table(
    entities: list[DataflowEntityInfo], language: str = "de"
) -> str:
    """Baut die Attribut-Tabelle über alle Entitäten hinweg."""
    rows = [
        (ent.name, attr)
        for ent in entities
        for attr in ent.attributes
    ]
    if not rows:
        return _t(
            language,
            "_Keine Attribute verfügbar._",
            "_No attributes available._",
        )
    header = _t(
        language,
        "| Entität | Attribut | Datentyp | Beschreibung |",
        "| Entity | Attribute | Data type | Description |",
    )
    lines = [header, "|---|---|---|---|"]
    for entity_name, attr in rows:
        lines.append(
            f"| {_escape_cell(entity_name)} | {_escape_cell(attr.name)} | "
            f"{_escape_cell(attr.data_type) or '–'} | "
            f"{_escape_cell(attr.description) or '–'} |"
        )
    return "\n".join(lines)


def build_queries_section(
    entities: list[DataflowEntityInfo], language: str = "de"
) -> str:
    """Baut den Abschnitt mit dem M-Ausdruck je Entität (als Codeblöcke)."""
    blocks: list[str] = []
    for ent in entities:
        expr = (ent.m_expression or "").strip()
        if not expr:
            continue
        blocks.append(f"#### {ent.name}\n\n```m\n{expr}\n```")
    if not blocks:
        return _t(
            language,
            "_Keine entitätsbezogenen M-Ausdrücke verfügbar._",
            "_No entity-level M expressions available._",
        )
    return "\n\n".join(blocks)


def build_mashup_section(document_m: str, language: str = "de") -> str:
    """Baut den Abschnitt mit dem vollständigen Mashup-/M-Dokument."""
    doc = (document_m or "").strip()
    if not doc:
        return _t(
            language,
            "_Kein Mashup-Dokument verfügbar (ggf. über die REST API nicht "
            "abrufbar)._",
            "_No mashup document available (may not be retrievable via the "
            "REST API)._",
        )
    return f"```m\n{doc}\n```"


def build_refresh_plan(
    schedule: RefreshScheduleInfo | None, language: str = "de"
) -> str:
    """Baut die Refresh-Übersicht (Tabelle) aus dem Aktualisierungszeitplan."""
    if schedule is None:
        return _t(
            language,
            "_Kein Aktualisierungszeitplan verfügbar._",
            "_No refresh schedule available._",
        )
    header = _t(
        language,
        "| Frequenz | Uhrzeiten | Zeitzone | Tage |",
        "| Frequency | Times | Time zone | Days |",
    )
    times = ", ".join(schedule.times) if schedule.times else "–"
    days = ", ".join(schedule.days) if schedule.days else "–"
    lines = [
        header,
        "|---|---|---|---|",
        f"| {_escape_cell(schedule.frequency) or '–'} | {_escape_cell(times)} | "
        f"{_escape_cell(schedule.timezone) or '–'} | {_escape_cell(days)} |",
    ]
    return "\n".join(lines)


def build_service_hint(generation: str, language: str = "de") -> str:
    """Baut den Hinweis zur Datenherkunft/Extraktion je Generation."""
    if (generation or "").lower() == "gen2":
        return _t(
            language,
            "> **Hinweis:** Dies ist ein **Dataflow Gen2** (Fabric). Die "
            "Transformationslogik wird aus dem Mashup-Dokument (`mashup.pq`) "
            "des Dataflow-Definitionsexports gelesen. Ist der Export nicht "
            "verfügbar, bleiben die M-Abschnitte leer.",
            "> **Note:** This is a **Dataflow Gen2** (Fabric). The "
            "transformation logic is read from the mashup document "
            "(`mashup.pq`) of the dataflow definition export. If the export is "
            "unavailable, the M sections remain empty.",
        )
    return _t(
        language,
        "> **Hinweis:** Dies ist ein **Dataflow Gen1** (Power BI). Die "
        "Transformationslogik stammt aus der `model.json`-Definition "
        "(Mashup-Dokument und Entitäts-Partitionen).",
        "> **Note:** This is a **Dataflow Gen1** (Power BI). The transformation "
        "logic is taken from the `model.json` definition (mashup document and "
        "entity partitions).",
    )


# ---------------------------------------------------------------------------
# Platzhalter-Werte & Rendering
# ---------------------------------------------------------------------------

# Manuell auszufüllende Platzhalter (erhalten einen lokalisierten Hinweis, damit
# das Dokument keine leeren Zellen enthält).
_MANUAL_PLACEHOLDERS = (
    "KONTAKT_BusinessOwner",
    "KONTAKT_BusinessOwnerMail",
    "KONTAKT_TechOwner",
    "KONTAKT_TechOwnerMail",
    "KONTAKT_DataSteward",
    "KONTAKT_DataStewardMail",
    "KONTAKT_Betrieb",
    "KONTAKT_BetriebMail",
    "DF_Fachbereich",
    "DF_Konzerndomaene",
    "DF_Zielsetzung",
    "DF_Anwendungsfall",
    "DF_Konsumenten",
    "DF_DatenquellenDetail",
    "DF_ParameterHinweis",
    "DF_NullHandling",
    "DF_ErrorHandling",
    "DF_Validierungsregeln",
    "DF_QueryFolding",
    "DF_PerformanceHinweise",
    "DF_Optimierungen",
    "DF_Monitoring",
    "DF_BekannteProbleme",
    "DF_Zugriffe",
    "DF_Labels",
    "DF_Risiken",
    "DF_Repository",
    "REVIEW_FachName",
    "REVIEW_FachDatum",
    "REVIEW_FachKommentar",
    "REVIEW_TechName",
    "REVIEW_TechDatum",
    "REVIEW_TechKommentar",
)


def build_dataflow_values(
    df: DataflowInfo, export_date: str, language: str = "de"
) -> dict[str, str]:
    """Baut das Platzhalter-Wörterbuch für die Dataflow-Vorlage."""
    hint = _manual_hint(language)
    dash = _none(language)

    values: dict[str, str] = {name: hint for name in _MANUAL_PLACEHOLDERS}
    values.update(
        {
            "DF_Name": df.name or dash,
            "DF_Beschreibung": df.description or dash,
            "DF_Generation": df.generation or "Gen1",
            "DF_ID": df.id or dash,
            "DF_WebUrl": df.web_url or dash,
            "DF_ConfiguredBy": df.configured_by or dash,
            "DF_ModifiedTime": df.modified_time or dash,
            "DF_ExportDatum": export_date,
            "DF_EntitaetenTabelle": build_entities_table(df.entities, language),
            "DF_AttributeTabelle": build_attributes_table(df.entities, language),
            "DF_Queries": build_queries_section(df.entities, language),
            "DF_MashupDokument": build_mashup_section(df.document_m, language),
            "DF_ServiceHinweis": build_service_hint(df.generation, language),
            "DF_RefreshPlan": build_refresh_plan(df.refresh_schedule, language),
            "DF_DatenquellenTabelle": _t(
                language,
                "_Datenquellen werden aus dem M-Dokument abgeleitet "
                "(siehe Abschnitt 6). Bitte fachlich ergänzen._",
                "_Data sources are derived from the M document (see section 6). "
                "Please complete from a business perspective._",
            ),
        }
    )
    return values


def render_dataflow(
    template_content: str,
    df: DataflowInfo,
    export_date: str,
    language: str = "de",
) -> str:
    """Rendert ein eigenständiges Dataflow-Dokument anhand der Vorlage."""
    values = build_dataflow_values(df, export_date, language)
    rendered, _warnings = TemplateRenderer().render(template_content, values)
    return rendered
