from __future__ import annotations

import csv
import threading
from dataclasses import asdict, dataclass
from datetime import datetime

from costrouter.models import CostTier, TIER_ORDER


@dataclass
class RoutingRecord:
    timestamp: datetime
    prompt_length: int
    tier: CostTier
    model_used: str
    router_type: str
    screener_cost: float
    call_cost: float
    total_cost: float
    max_cost_estimate: float
    latency_ms: float


class Analytics:
    """Tracks routing decisions and costs."""

    def __init__(self) -> None:
        self._records: list[RoutingRecord] = []
        self._lock = threading.Lock()

    @property
    def records(self) -> list[RoutingRecord]:
        with self._lock:
            return list(self._records)

    def record(self, record: RoutingRecord) -> None:
        with self._lock:
            self._records.append(record)

    def summary(self) -> str:
        with self._lock:
            records = list(self._records)

        if not records:
            return "CostRouter Analytics\n====================\nNo requests recorded."

        total_requests = len(records)
        total_cost = sum(r.total_cost for r in records)
        screening_costs = sum(r.screener_cost for r in records)
        max_cost = sum(r.max_cost_estimate for r in records)
        saved = max_cost - total_cost
        pct = (saved / max_cost * 100) if max_cost > 0 else 0

        lines = [
            "CostRouter Analytics",
            "====================",
            f"Total requests: {total_requests}",
            f"Total cost: ${total_cost:.2f}",
            f"Screening costs: ${screening_costs:.2f}",
            f"Cost if always using most expensive: ${max_cost:.2f}",
            f"Total saved: ${saved:.2f} ({pct:.0f}%)",
            "",
            "Routing breakdown:",
        ]

        tier_counts: dict[CostTier, list[RoutingRecord]] = {}
        for r in records:
            tier_counts.setdefault(r.tier, []).append(r)

        for tier in TIER_ORDER:
            tier_records = tier_counts.get(tier, [])
            count = len(tier_records)
            pct_tier = (count / total_requests * 100) if total_requests > 0 else 0
            if tier_records:
                models_used = set(r.model_used for r in tier_records)
                model_str = ", ".join(sorted(models_used))
                lines.append(
                    f"  {tier.value:10s} {pct_tier:5.1f}% ({count} requests)  -> {model_str}"
                )
            else:
                lines.append(f"  {tier.value:10s}   0.0% (0 requests)")

        return "\n".join(lines)

    def to_dict(self) -> dict:
        with self._lock:
            records = list(self._records)

        total_cost = sum(r.total_cost for r in records)
        max_cost = sum(r.max_cost_estimate for r in records)
        return {
            "total_requests": len(records),
            "total_cost": total_cost,
            "screening_costs": sum(r.screener_cost for r in records),
            "max_cost_estimate": max_cost,
            "saved": max_cost - total_cost,
            "records": [asdict(r) for r in records],
        }

    def to_records(self) -> list[dict]:
        with self._lock:
            records = list(self._records)
        return [asdict(r) for r in records]

    def export_csv(self, path: str) -> None:
        with self._lock:
            records = list(self._records)

        if not records:
            return

        fieldnames = list(asdict(records[0]).keys())
        with open(path, "w", newline="") as f:
            writer = csv.DictWriter(f, fieldnames=fieldnames)
            writer.writeheader()
            for record in records:
                row = asdict(record)
                row["tier"] = row["tier"].value if hasattr(row["tier"], "value") else row["tier"]
                writer.writerow(row)

    def reset(self) -> None:
        with self._lock:
            self._records.clear()
