"""Vizro Inventory Cross-Validation Dashboard.

Loads cross-validation JSON evidence and renders interactive charts.
Run: python -m runbooks.inventory.vizro_dashboard
Docker: docker compose exec jupyter python -m runbooks.inventory.vizro_dashboard
"""

import json
import sys
from pathlib import Path

import pandas as pd
import plotly.express as px
import plotly.graph_objects as go

try:
    import vizro.models as vm
    from vizro import Vizro
    from vizro.managers import data_manager
    from vizro.models.types import capture
except ImportError:
    print("Vizro not installed. Run: pip install 'vizro>=0.1.46'")
    sys.exit(1)


# ── Data Loading ──────────────────────────────────────────────
DEFAULT_EVIDENCE = "tmp/runbooks/cross-validation"


def load_cross_validation_data(evidence_dir: str = DEFAULT_EVIDENCE) -> pd.DataFrame:
    """Load the latest cross-validation JSON evidence into a DataFrame.

    Reads the ``per_type`` dict from cross-validate-*.json evidence files
    produced by ``runbooks inventory cross-validate --export-json``.
    Falls back to sample data when no evidence files exist.
    """
    evidence_path = Path(evidence_dir)
    json_files = sorted(evidence_path.glob("cross-validate-*.json")) if evidence_path.exists() else []
    # Also accept generic *.json files (legacy paths)
    if not json_files and evidence_path.exists():
        json_files = sorted(evidence_path.glob("*.json"))

    if json_files:
        with open(json_files[-1]) as f:
            data = json.load(f)
        per_type = data.get("per_type", {})
        if per_type:
            rows = []
            for rtype, m in per_type.items():
                rows.append(
                    {
                        "type": rtype,
                        "v1_count": m.get("v1", 0),
                        "v2_count": m.get("v2", 0),
                        "accuracy": m.get("accuracy") if m.get("accuracy") is not None else 0.0,
                        "status": m.get("status", "N/A"),
                    }
                )
            return pd.DataFrame(rows)
    return _sample_data()


def _sample_data() -> pd.DataFrame:
    """Sample data for demo mode (no live evidence available)."""
    return pd.DataFrame(
        {
            "type": ["ec2", "rds", "s3", "lambda", "vpc", "cloudformation", "ebs"],
            "v1_count": [145, 23, 89, 67, 12, 34, 78],
            "v2_count": [142, 23, 87, 65, 12, 33, 76],
            "matched": [140, 23, 86, 64, 12, 33, 75],
            "accuracy": [96.6, 100.0, 97.7, 95.5, 100.0, 97.1, 97.4],
            "status": ["WARN", "PASS", "WARN", "WARN", "PASS", "WARN", "WARN"],
            "persona": ["all"] * 7,
        }
    )


# ── Chart Builders ────────────────────────────────────────────
@capture("graph")
def accuracy_bar(data_frame: pd.DataFrame) -> go.Figure:
    """Accuracy by resource type with PASS/WARN/FAIL thresholds."""
    df_valid = data_frame[data_frame["status"] != "N/A"].copy()
    fig = px.bar(
        df_valid,
        x="type",
        y="accuracy",
        color="status",
        color_discrete_map={"PASS": "#22c55e", "WARN": "#f97316", "FAIL": "#ef4444"},
        title="Cross-Validation Accuracy by Resource Type",
    )
    fig.add_hline(y=99.5, line_dash="dash", line_color="green", annotation_text="PASS")
    fig.add_hline(y=95.0, line_dash="dash", line_color="orange", annotation_text="WARN")
    fig.update_layout(yaxis_range=[85, 101], template="plotly_dark")
    return fig


@capture("graph")
def v1_v2_comparison(data_frame: pd.DataFrame) -> go.Figure:
    """Side-by-side V1 vs V2 resource count comparison."""
    df_valid = data_frame[data_frame["status"] != "N/A"].copy()
    fig = go.Figure(
        data=[
            go.Bar(name="Config Aggregator (V1)", x=df_valid["type"], y=df_valid["v1_count"], marker_color="#6366f1"),
            go.Bar(name="Resource Explorer (V2)", x=df_valid["type"], y=df_valid["v2_count"], marker_color="#0ea5e9"),
        ]
    )
    fig.update_layout(barmode="group", title="V1 vs V2 Resource Count", template="plotly_dark")
    return fig


@capture("graph")
def resource_distribution(data_frame: pd.DataFrame) -> go.Figure:
    """Total resource distribution by type (pie chart)."""
    fig = px.pie(
        data_frame,
        names="type",
        values="v1_count",
        title="Resource Distribution by Type",
        color_discrete_sequence=px.colors.qualitative.Set3,
    )
    fig.update_layout(template="plotly_dark")
    return fig


@capture("graph")
def accuracy_gauge(data_frame: pd.DataFrame) -> go.Figure:
    """Overall accuracy gauge."""
    df_valid = data_frame[data_frame["status"] != "N/A"]
    overall = df_valid["accuracy"].mean() if not df_valid.empty else 0
    fig = go.Figure(
        go.Indicator(
            mode="gauge+number",
            value=overall,
            title={"text": "Overall Accuracy"},
            gauge={
                "axis": {"range": [80, 100]},
                "bar": {"color": "#6366f1"},
                "steps": [
                    {"range": [80, 95], "color": "#fee2e2"},
                    {"range": [95, 99.5], "color": "#fef3c7"},
                    {"range": [99.5, 100], "color": "#dcfce7"},
                ],
                "threshold": {"line": {"color": "#22c55e", "width": 4}, "thickness": 0.75, "value": 99.5},
            },
        )
    )
    fig.update_layout(template="plotly_dark", height=300)
    return fig


# ── Dashboard Assembly ────────────────────────────────────────
def build_dashboard(evidence_dir: str = DEFAULT_EVIDENCE) -> Vizro:
    """Build the Vizro dashboard with 4 charts."""
    df = load_cross_validation_data(evidence_dir)

    # Register static data with Vizro data_manager; chart functions are called
    # with the string key so Vizro resolves the DataFrame at render time.
    data_manager["cross_validation"] = df

    page = vm.Page(
        title="Inventory Cross-Validation",
        components=[
            vm.Graph(figure=accuracy_gauge(data_frame="cross_validation")),
            vm.Graph(figure=accuracy_bar(data_frame="cross_validation")),
            vm.Graph(figure=v1_v2_comparison(data_frame="cross_validation")),
            vm.Graph(figure=resource_distribution(data_frame="cross_validation")),
        ],
        layout=vm.Grid(grid=[[0, 1], [2, 3]]),
    )

    dashboard = vm.Dashboard(pages=[page])
    return Vizro().build(dashboard)


# ── CLI Entry Point ───────────────────────────────────────────
if __name__ == "__main__":
    evidence = sys.argv[1] if len(sys.argv) > 1 else DEFAULT_EVIDENCE
    app = build_dashboard(evidence)
    print("Starting Vizro dashboard at http://localhost:8050")
    app.run(host="0.0.0.0", port=8050)
