from __future__ import annotations

from decimal import Decimal
from typing import Any

from jarvis_finance.dashboard.components.tables import show_table
from jarvis_finance.dashboard import data
from jarvis_finance.services.portfolio_advisor import get_portfolio_advisor_snapshot

PAGE_TITLE = "Portfolio Übersicht"
PALETTE = ["#2563eb", "#14b8a6", "#f59e0b", "#a855f7", "#f97316", "#64748b", "#22c55e"]


def _plotly_donut(st, title: str, rows: list[dict[str, str]]) -> None:
    st.markdown(f"**{title}**")
    chart_rows = [row for row in rows if data.d(row["current_value_chf"]) > 0]
    if not chart_rows:
        st.info("Noch keine bewerteten Positionen vorhanden.")
        return
    try:
        import plotly.graph_objects as go

        fig = go.Figure(
            data=[
                go.Pie(
                    labels=[row["label"] for row in chart_rows],
                    values=[float(data.d(row["current_value_chf"])) for row in chart_rows],
                    hole=0.58,
                    marker={"colors": PALETTE[: len(chart_rows)]},
                    textinfo="label+percent",
                    hovertemplate="%{label}<br>%{percent}<extra></extra>",
                )
            ]
        )
        fig.update_layout(
            margin={"l": 8, "r": 8, "t": 12, "b": 8},
            height=330,
            showlegend=True,
            legend={"orientation": "h", "y": -0.1},
        )
        st.plotly_chart(fig, use_container_width=True, config={"displayModeBar": False})
    except Exception:
        st.bar_chart({row["label"]: float(data.d(row["current_value_chf"])) for row in chart_rows})


def _slice_rows(items) -> list[dict[str, str]]:
    return [
        {
            "Bereich": item.label,
            "Wert CHF": data.chf_text(Decimal(item.current_value_chf)),
            "Ist": f"{item.current_pct}%",
            "Ziel": f"{item.target_pct}%",
            "Drift": f"{item.drift_pct}%",
            "Status": item.status,
            "Empfehlung": item.recommendation,
            "Drilldown": " → ".join(item.drilldown),
        }
        for item in items
    ]


def _drilldown_rows(snapshot: Any, selected_key: str) -> list[dict[str, str]]:
    selected = next((item for item in snapshot.asset_allocation if item.key == selected_key), None)
    if not selected:
        return []
    child_nodes = [node for node in snapshot.drilldown_nodes if node.parent_key == selected_key]
    if child_nodes:
        return [
            {
                "Ebene": node.label,
                "Anteil": f"{node.current_pct}%",
                "Status": node.status,
                "Hinweis": node.note,
            }
            for node in child_nodes
        ]
    return [
        {
            "Ebene": label,
            "Anteil": "offen",
            "Status": "placeholder",
            "Hinweis": "Drilldown vorbereitet; echte Werte folgen aus Datenimport/Lookthrough.",
        }
        for label in selected.drilldown
    ]


def _lookthrough_rows(snapshot: Any, source_key: str | None = None) -> list[dict[str, str]]:
    rows = snapshot.lookthrough_placeholders
    if source_key:
        rows = [row for row in rows if row.source_key == source_key]
    return [
        {
            "Quelle": row.label,
            "Typ": row.instrument_type,
            "Status": row.status,
            "Dimensionen": " · ".join(row.dimensions),
            "Nächster Schritt": row.next_step,
        }
        for row in rows
    ]


def _import_rows(snapshot: Any) -> list[dict[str, str]]:
    return [
        {
            "Quelle": source.label,
            "Dateien": " · ".join(source.expected_files),
            "Mapping": " · ".join(source.mapped_to),
            "Status": source.status,
            "Nächster Schritt": source.next_step,
        }
        for source in snapshot.import_sources
    ]


def render(st, conn) -> None:
    snapshot = get_portfolio_advisor_snapshot(conn)
    st.title(snapshot.title)
    st.caption("TrueWealth-Ersatz im geschützten Finanzdashboard: genaue lokale Werte, Drilldown-Struktur, Strategie, Risiko/Rendite und Rebalancing-Preview. Keine Auto-Ausführung.")

    c1, c2, c3, c4 = st.columns(4)
    c1.metric("Gesamtvermögen", data.chf_text(Decimal(snapshot.total_value_chf)))
    c2.metric("Datenqualität", data.translate_status(snapshot.data_quality_status))
    c3.metric("Letztes Preisupdate", data.date_text(snapshot.last_price_update))
    c4.metric("Ausführung", "gesperrt")

    st.subheader("Cockpit")
    left, right = st.columns(2)
    with left:
        _plotly_donut(st, "Quelle / Vermögensbereich", [item.model_dump() for item in snapshot.source_allocation])
    with right:
        _plotly_donut(st, "Asset Allocation", [item.model_dump() for item in snapshot.asset_allocation])

    st.markdown("### Klickbarer Drilldown")
    selected_label = st.selectbox(
        "Donut-Segment für Drilldown auswählen",
        [item.label for item in snapshot.asset_allocation],
        key="portfolio_advisor_drilldown_segment",
    )
    selected_key = next(item.key for item in snapshot.asset_allocation if item.label == selected_label)
    show_table(st, _drilldown_rows(snapshot, selected_key))

    tab_allocation, tab_positions, tab_risk, tab_strategy, tab_audit, tab_import = st.tabs(["Allokation", "Positionen & Lookthrough", "Risiko & Rendite", "Strategie", "Preview / Audit", "TrueWealth Import"])

    with tab_allocation:
        st.markdown("### Ist vs Ziel")
        show_table(st, _slice_rows(snapshot.asset_allocation))
        st.markdown("### Quellen")
        show_table(st, _slice_rows(snapshot.source_allocation))

    with tab_positions:
        st.markdown("### Modellierte Detailtabs")
        st.write(" · ".join(snapshot.tabs))
        st.info("ETF-/TrueWealth-Lookthrough ist als nächster Import-/Mapping-Schritt vorgesehen: ISIN → Holdings → Regionen/Sektoren/Währungen/Unternehmen.")
        source_filter = st.selectbox(
            "Lookthrough-Quelle",
            ["Alle"] + [row.label for row in snapshot.lookthrough_placeholders],
            key="portfolio_advisor_lookthrough_source",
        )
        selected_source = None
        if source_filter != "Alle":
            selected_source = next(row.source_key for row in snapshot.lookthrough_placeholders if row.label == source_filter)
        show_table(st, _lookthrough_rows(snapshot, selected_source))

    with tab_risk:
        st.markdown("### Risiko & Rendite Bereich")
        show_table(st, [
            {"Bereich": "Performance", "Inhalt": "TWR/MWR, Ein-/Auszahlungen, Kosten, Währungseffekt"},
            {"Bereich": "Beitrag", "Inhalt": "Renditebeitrag nach Anlageklasse und Quelle"},
            {"Bereich": "Benchmarking", "Inhalt": "Portfolio vs Zielportfolio / SPI / MSCI World / S&P 500 / Cash"},
            {"Bereich": "Simulierte Historie", "Inhalt": "historische Allokation, Drawdown, beste/schlechteste Perioden"},
            {"Bereich": "Risiko", "Inhalt": "Volatilität, Verlustwahrscheinlichkeit, Anlagehorizont"},
        ])

    with tab_strategy:
        st.markdown("### Strategie-Editor Zielbild")
        show_table(st, [
            {"Regel": "Zielallokation", "Status": "vorbereitet"},
            {"Regel": "Toleranzbänder", "Status": "vorbereitet"},
            {"Regel": "Region-/Sektorlimits", "Status": "vorbereitet"},
            {"Regel": "Crypto-Maximum", "Status": "vorbereitet"},
            {"Regel": "Cash-Minimum", "Status": "vorbereitet"},
            {"Regel": "Einzelpositionsmaximum", "Status": "vorbereitet"},
        ])
        st.warning("Strategieänderungen erzeugen später nur Vorschläge. Keine Order-Ausführung aus dem Dashboard.")

    with tab_audit:
        st.markdown("### Preview → Confirm → Audit")
        show_table(st, [step.model_dump() for step in snapshot.workflow])
        st.markdown("### Guardrails")
        for guardrail in snapshot.guardrails:
            st.write(f"- {guardrail}")
        st.markdown("### Scorecards")
        show_table(st, [card.model_dump() for card in snapshot.scorecards])

    with tab_import:
        st.markdown("### TrueWealth Screens/PDFs → Portfolio Advisor Modell")
        st.caption("Import-Zielbild: Rohdateien bleiben lokal/Drive; das Dashboard speichert strukturierte Allokations-, Performance- und Renditebeitragsdaten.")
        show_table(st, _import_rows(snapshot))
        st.warning("Noch Preview-Status: Parser/OCR-Mapping wird als nächster Schritt implementiert; keine Roh-PDFs oder Screenshots werden ins Git übernommen.")
