"""Dashboard screen — project overview with stats."""

from __future__ import annotations

from datetime import datetime, timedelta, timezone

from textual import on
from textual.app import ComposeResult
from textual.binding import Binding
from textual.containers import Horizontal, Vertical
from textual.screen import Screen
from textual.widgets import Button, Footer, Header, Static


class DashboardScreen(Screen):
    BINDINGS = [
        Binding("g", "grade", "Grade"),
        Binding("d", "dataset", "Dataset"),
        Binding("b", "go_back", "Back"),
        Binding("r", "refresh", "Refresh", show=True),
        Binding("q", "quit", "Quit", show=True),
    ]

    def compose(self) -> ComposeResult:
        yield Header()
        with Horizontal(id="dashboard-layout"):
            with Vertical(id="main-panel"):
                yield Static("", id="project-header")
                with Horizontal(id="actions-row"):
                    yield Button("Grade", id="btn-grade", variant="primary")
                    yield Button("Dataset", id="btn-dataset", variant="default")
                with Horizontal(id="stats-row"):
                    yield Static("", id="stat-traces")
                    yield Static("", id="stat-grading")
                    yield Static("", id="stat-averages")
                yield Static("", id="model-breakdown")
                yield Static("", id="span-breakdown")
        yield Footer()

    def on_mount(self) -> None:
        self._load_project()

    @on(Button.Pressed, "#btn-grade")
    def on_grade_pressed(self) -> None:
        self.action_grade()

    @on(Button.Pressed, "#btn-dataset")
    def on_dataset_pressed(self) -> None:
        self.action_dataset()

    def _load_project(self) -> None:
        from ..app import BanditoApp
        from ...retrieval import get_retrieval

        app: BanditoApp = self.app
        project = app.project
        if not project:
            self.query_one("#project-header", Static).update("[red]No project selected[/red]")
            return
        r = get_retrieval(project)

        evals = r.evals()

        if app.client:
            traces = r.traces(tier="trace", limit=1000)
            data = app.client.analyze_basics(traces, evals or None)
            stats = data["stats"]
        else:
            from ...review.aggregator import aggregate_summaries
            from dataclasses import asdict
            summaries = r.traces(tier="summary")
            stats = asdict(aggregate_summaries(summaries, evals))

        cost = stats["cost"]
        latency = stats["latency"]
        tokens = stats["tokens"]

        self.query_one("#project-header", Static).update(
            f"[bold]{project}[/bold]"
        )

        trace_summaries = r.traces(tier="summary")
        daily: dict[str, int] = {}
        for t in trace_summaries:
            started = t.get("started_at", "")
            if started:
                try:
                    dt = datetime.fromisoformat(started.replace("Z", "+00:00"))
                    daily[dt.strftime("%Y-%m-%d")] = daily.get(dt.strftime("%Y-%m-%d"), 0) + 1
                except (ValueError, TypeError):
                    pass
        today = datetime.now(timezone.utc).date()
        daily_counts = [
            daily.get((today - timedelta(days=6 - i)).isoformat(), 0)
            for i in range(7)
        ]
        spark_chars = " ▁▂▃▄▅▆▇█"
        max_val = max(daily_counts) if any(daily_counts) else 1
        sparkline = "".join(
            spark_chars[min(int(v / max_val * 8), 8)]
            for v in daily_counts
        )
        total_trace_count = len(trace_summaries)
        self.query_one("#stat-traces", Static).update(
            f"[bold]Traces (7d)[/bold]\n"
            f"[cyan]{total_trace_count}[/cyan] total\n"
            f"[dim]{sparkline}[/dim]\n"
            f"[dim]Mon─────Sun[/dim]"
        )

        ungraded = stats["trace_count"] - stats.get("eval_count", 0)

        human_avg = f"{stats['human_avg_grade']:.2f}" if stats.get("human_avg_grade") is not None else "—"
        judge_avg = f"{stats['judge_avg_grade']:.2f}" if stats.get("judge_avg_grade") is not None else "—"
        self.query_one("#stat-grading", Static).update(
            f"[bold]Grading[/bold]\n"
            f"[green]{stats.get('human_eval_count', 0)}[/green] human (avg [cyan]{human_avg}[/cyan])\n"
            f"[magenta]{stats.get('judge_eval_count', 0)}[/magenta] judge (avg [cyan]{judge_avg}[/cyan])\n"
            f"[yellow]{ungraded}[/yellow] ungraded"
        )

        self.query_one("#stat-averages", Static).update(
            f"[bold]Cost & Performance[/bold]\n"
            f"Total:   [cyan]${cost['total']:.4f}[/cyan]\n"
            f"Avg:     [cyan]${cost['mean']:.4f}[/cyan]\n"
            f"Latency: [cyan]{latency['mean']:.1f}s[/cyan]\n"
            f"Tokens:  [cyan]{tokens['mean']:.0f}[/cyan]"
        )

        # Model breakdown
        models = stats.get("models", [])
        if models:
            m_lines = ["[bold]Models[/bold]"]
            for m in sorted(models, key=lambda x: -x.get("total_cost", 0)):
                name = m["model"]
                if m.get("provider"):
                    name = f"{m['model']} [dim]({m['provider']})[/dim]"
                count = m["count"]
                avg_cost = m["total_cost"] / count if count else 0
                m_lines.append(
                    f"  {name}\n"
                    f"    [cyan]{count}[/cyan] calls · "
                    f"[cyan]${m['total_cost']:.4f}[/cyan] total · "
                    f"[cyan]${avg_cost:.4f}[/cyan] avg"
                )
            self.query_one("#model-breakdown", Static).update("\n".join(m_lines))
        else:
            self.query_one("#model-breakdown", Static).update("")

        # Span kinds
        span_kinds = stats.get("span_kinds", [])
        total_spans = sum(sk["count"] for sk in span_kinds) or 1
        lines = ["[bold]Span Kinds[/bold]"]
        for sk in sorted(span_kinds, key=lambda x: -x["count"]):
            pct_val = sk["count"] / total_spans
            bar_width = 30
            filled = int(pct_val * bar_width)
            bar = "█" * filled + "░" * (bar_width - filled)
            lines.append(f"  {sk['kind']:<12} [cyan]{bar}[/cyan]  {pct_val:>4.0%}")
        self.query_one("#span-breakdown", Static).update("\n".join(lines))

    def action_refresh(self) -> None:
        self._load_project()

    def action_grade(self) -> None:
        from .grading import GradingScreen

        self.app.push_screen(GradingScreen())

    def action_dataset(self) -> None:
        self.notify("Dataset screen coming soon")

    def action_go_back(self) -> None:
        from .project_picker import ProjectPickerScreen
        self.app.push_screen(ProjectPickerScreen())

    def action_quit(self) -> None:
        self.app.exit()
