from __future__ import annotations

from pathlib import Path

from jarvis_finance.config.paths import RuntimePaths
from jarvis_finance.config.settings import Settings, load_settings
from jarvis_finance.dashboard.components.tables import show_table
from jarvis_finance.dashboard import data
from jarvis_finance.market.providers import CoinGeckoClient, refresh_crypto_prices
from jarvis_finance.market_data.prices import equity_price_provider_by_name, refresh_market_prices
from jarvis_finance.reports.crypto_inventory import export_crypto_inventory_report

PAGE_TITLE = "Command Center"


def _metric_row(st, metrics: list[tuple[str, str, str | None]]) -> None:
    cols = st.columns(len(metrics))
    for col, (label, value, help_text) in zip(cols, metrics):
        col.metric(label, value, help=help_text)


def _report_settings(st) -> Settings:
    runtime_override = st.session_state.get("jarvis_reports_runtime_dir") if hasattr(st, "session_state") else None
    if runtime_override:
        return Settings(runtime_paths=RuntimePaths.from_base(Path(str(runtime_override))))
    return load_settings()


def _request_position_add(st) -> None:
    if hasattr(st, "session_state"):
        st.session_state["jarvis_requested_page"] = "Position hinzufügen"


def _equity_label(summary: dict[str, str], key: str) -> str:
    unvalued = data.d(summary.get("unvalued_position_count"))
    value = data.d(summary.get(key))
    if value <= 0 and unvalued > 0:
        return "nicht vollständig bewertet"
    if unvalued > 0:
        return f"{data.chf_text(value)} + offen"
    return data.chf_text(value)


def _price_refresh_message(crypto_result, stock, etf, summary: dict[str, str]) -> str:
    equity_checked = stock.total_mappings + etf.total_mappings
    equity_updated = stock.updated_count + etf.updated_count
    equity_skipped = stock.skipped_count + etf.skipped_count + stock.cached_count + etf.cached_count
    return (
        f"Preisupdate abgeschlossen — Crypto: aktualisiert {crypto_result.updated_count}, ohne Preis {crypto_result.missing_local_price_count}, "
        f"Hinweise/Fehler {crypto_result.warning_count}/{crypto_result.error_count}. "
        f"Aktien/ETFs: geprüft {equity_checked}, aktualisiert {equity_updated}, Cache/übersprungen {equity_skipped}, "
        f"weiterhin ohne Preis {summary.get('missing_price_count', '0')}, ohne FX {summary.get('missing_fx_count', '0')}. "
        "Provider: Crypto CoinGecko; Aktien/ETFs auto = FMP → Twelve Data → Finnhub → Massive."
    )


def render(st, conn) -> None:
    st.title("Command Center")
    st.caption("Ruhige Startseite: wichtigste Werte, getrennte Summen, wenige Hinweise, direkte MVP-Aktionen. Keine API-Abfragen beim Laden.")
    summary = data.get_command_center_summary(conn)
    _metric_row(st, [
        ("Gesamtportfolio CHF", data.chf_text(summary["total_portfolio_chf"]), "Nur vollständig bewertete Positionen; offene Preise/FX werden separat gezählt."),
        ("Cash CHF", data.chf_text(summary["cash_total_chf"]), None),
        ("Aktien CHF", _equity_label(summary, "stock_total_chf"), "Wird als offen markiert, solange Marktpreise oder FX fehlen."),
        ("ETFs CHF", _equity_label(summary, "etf_total_chf"), "Wird als offen markiert, solange Marktpreise oder FX fehlen."),
        ("Crypto CHF", data.chf_text(summary["crypto_total_chf"]), None),
    ])
    _metric_row(st, [
        ("Unbewertete Positionen", summary.get("unvalued_position_count", "0"), "Marktpreis oder FX fehlt."),
        ("Ohne Preis", summary.get("missing_price_count", "0"), "Aktien/ETFs ohne lokalen Marktpreis."),
        ("Ohne FX", summary.get("missing_fx_count", "0"), "Fremdwährungspositionen ohne CHF-Umrechnung."),
        ("Kritische Punkte", summary["critical_alert_count"], "aktive kritische Hinweise"),
        ("Letztes Preisupdate", data.date_text(summary["last_price_update_at"]), None),
    ])

    if data.d(summary.get("unvalued_position_count")) > 0:
        st.info("Portfolio: Bewertung unvollständig. User Mode zeigt keine irreführenden CHF-0-Werte; offene Preise/FX sind separat sichtbar.")

    st.subheader("Was ist wichtig?")
    hints = data.get_top_user_hints(conn, limit=3)
    if not hints:
        st.success("Keine wichtigen Hinweise.")
    for hint in hints[:3]:
        st.markdown(f"**Wichtig:** {hint}")

    st.subheader("Top 5 Crypto-Positionen")
    crypto_rows = data.get_crypto_coin_summary(conn)[:5]
    show_table(st, [{k: r[k] for k in ["coin", "symbol", "gesamtwert_chf", "anteil", "status"] if k in r} for r in crypto_rows])

    st.subheader("Schnellaktionen")
    a, b, c, d = st.columns(4)
    if a.button("+ Position hinzufügen", key="cc_position_add", on_click=_request_position_add, args=(st,)):
        a.success("Öffne die User-Mode-Seite „Position hinzufügen“. Dort startet der Wizard.")
    if b.button("Preise aktualisieren", key="cc_price_refresh"):
        b.spinner("Lokale CHF-Preise werden aktualisiert …")
        crypto_result = refresh_crypto_prices(conn, provider=CoinGeckoClient(max_retries=2, initial_backoff_seconds=1.0, max_backoff_seconds=8.0), currency="CHF", only_missing=True, sleep_seconds=1.0)
        stock = refresh_market_prices(conn, provider=equity_price_provider_by_name("auto"), asset_class="stock", only_missing=True)
        etf = refresh_market_prices(conn, provider=equity_price_provider_by_name("auto"), asset_class="etf", only_missing=True)
        summary = data.get_command_center_summary(conn)
        b.success(_price_refresh_message(crypto_result, stock, etf, summary))
    if b.button("Crypto-Report erzeugen", key="cc_crypto_report"):
        try:
            b.spinner("Crypto-Report wird aus lokalen Daten erzeugt …")
            result = export_crypto_inventory_report(conn, settings=_report_settings(st), preferred_format="pdf")
            b.success(f"Report erzeugt ({result['format']}): {result['file_path']}")
        except Exception as exc:
            b.error(f"Report konnte nicht erzeugt werden: {exc}")
    c.button("Coin hinzufügen", key="cc_coin_add", disabled=True, help="Bitte auf der Crypto-Seite eine Position auswählen; dort öffnet das Formular direkt.")
    d.button("Wallet öffnen", key="cc_wallet_open", disabled=True, help="Bitte die Wallets-Seite über die Hauptnavigation öffnen; dort ist die Auswahl direkt sichtbar.")

    alerts = data.get_alert_summary_cards(conn)
    st.caption(f"Hinweise zusammengefasst — Kritisch: {alerts['kritisch']} · Wichtig: {alerts['wichtig']} · Info: {alerts['info']}")
