"""
Langfuse Analytics — Data retrieval wrapper for AI Report Agent.
Uses Langfuse SDK v3 + REST API to fetch traces, scores, metrics.
"""

import logging
from datetime import datetime, timedelta, timezone
from typing import Any

import httpx

from config import LANGFUSE_BASE_URL, LANGFUSE_PUBLIC_KEY, LANGFUSE_SECRET_KEY

logger = logging.getLogger(__name__)

__all__ = ["LangfuseAnalytics"]


class LangfuseAnalytics:
    """Fetch analytics data from Langfuse for report generation."""

    def __init__(self):
        self._base_url = (LANGFUSE_BASE_URL or "https://cloud.langfuse.com").rstrip("/")
        self._auth = (LANGFUSE_PUBLIC_KEY or "", LANGFUSE_SECRET_KEY or "")
        self._available = bool(LANGFUSE_PUBLIC_KEY and LANGFUSE_SECRET_KEY)

    @property
    def available(self) -> bool:
        return self._available

    # ─── REST helpers ────────────────────────────────────────────────

    async def _get(self, path: str, params: dict | None = None) -> dict:
        """Make authenticated GET request to Langfuse API."""
        url = f"{self._base_url}/api/public{path}"
        async with httpx.AsyncClient(timeout=30) as client:
            resp = await client.get(url, params=params, auth=self._auth)
            resp.raise_for_status()
            return resp.json()

    # ─── Daily Metrics ───────────────────────────────────────────────

    async def get_daily_metrics(
        self,
        from_date: str | None = None,
        to_date: str | None = None,
        trace_name: str | None = None,
        limit: int = 30,
    ) -> dict[str, Any]:
        """
        Fetch daily aggregated metrics (traces, cost, models).
        Uses GET /api/public/metrics/daily
        """
        if not self._available:
            return {"error": "Langfuse not configured", "data": []}

        now = datetime.now(timezone.utc)
        params: dict[str, Any] = {"limit": limit}

        if from_date:
            params["fromTimestamp"] = from_date
        else:
            params["fromTimestamp"] = (now - timedelta(days=30)).strftime("%Y-%m-%dT00:00:00Z")

        if to_date:
            params["toTimestamp"] = to_date

        if trace_name:
            params["traceName"] = trace_name

        try:
            result = await self._get("/metrics/daily", params)
            data = result.get("data", [])
            logger.info("📊 Langfuse daily metrics: %d days", len(data))
            return {
                "data": data,
                "total_days": len(data),
                "summary": self._summarize_daily(data),
            }
        except Exception as e:
            logger.error("❌ Langfuse daily metrics error: %s", e)
            return {"error": str(e), "data": []}

    def _summarize_daily(self, data: list[dict]) -> dict:
        """Compute summary stats from daily metrics."""
        if not data:
            return {}

        total_traces = sum(d.get("countTraces", 0) for d in data)
        total_observations = sum(d.get("countObservations", 0) for d in data)
        total_cost = sum(d.get("totalCost", 0) or 0 for d in data)

        # Model breakdown
        model_usage: dict[str, int] = {}
        for day in data:
            for u in day.get("usage", []):
                model = u.get("model", "unknown")
                model_usage[model] = model_usage.get(model, 0) + u.get("countObservations", 0)

        avg_traces_per_day = total_traces / len(data) if data else 0

        return {
            "total_traces": total_traces,
            "total_observations": total_observations,
            "total_cost_usd": round(total_cost, 4),
            "avg_traces_per_day": round(avg_traces_per_day, 1),
            "days_count": len(data),
            "model_usage": dict(sorted(model_usage.items(), key=lambda x: x[1], reverse=True)),
        }

    # ─── Traces ──────────────────────────────────────────────────────

    async def get_traces_summary(
        self,
        from_date: str | None = None,
        to_date: str | None = None,
        limit: int = 50,
    ) -> dict[str, Any]:
        """
        Fetch recent traces list with metadata.
        Uses GET /api/public/traces
        """
        if not self._available:
            return {"error": "Langfuse not configured", "data": []}

        params: dict[str, Any] = {"limit": limit, "orderBy": "timestamp.desc"}
        if from_date:
            params["fromTimestamp"] = from_date
        if to_date:
            params["toTimestamp"] = to_date

        try:
            result = await self._get("/traces", params)
            traces = result.get("data", [])

            # Extract useful fields
            simplified = []
            for t in traces:
                simplified.append({
                    "id": t.get("id", "")[:12],
                    "name": t.get("name", ""),
                    "userId": t.get("userId", ""),
                    "sessionId": t.get("sessionId", ""),
                    "timestamp": t.get("timestamp", ""),
                    "latency_ms": t.get("latency"),
                    "totalCost": t.get("totalCost"),
                    "observationCount": t.get("observationCount", 0),
                    "tags": t.get("tags", []),
                })

            # Compute stats
            latencies = [t["latency_ms"] for t in simplified if t["latency_ms"] is not None]
            unique_users = len(set(t["userId"] for t in simplified if t["userId"]))
            unique_sessions = len(set(t["sessionId"] for t in simplified if t["sessionId"]))

            logger.info("📊 Langfuse traces: %d traces, %d users", len(simplified), unique_users)
            return {
                "data": simplified,
                "total_traces": len(simplified),
                "unique_users": unique_users,
                "unique_sessions": unique_sessions,
                "avg_latency_ms": round(sum(latencies) / len(latencies), 0) if latencies else None,
                "p95_latency_ms": round(sorted(latencies)[int(len(latencies) * 0.95)] if latencies else 0, 0),
            }
        except Exception as e:
            logger.error("❌ Langfuse traces error: %s", e)
            return {"error": str(e), "data": []}

    # ─── Scores ──────────────────────────────────────────────────────

    async def get_scores_summary(
        self,
        from_date: str | None = None,
        to_date: str | None = None,
        limit: int = 200,
    ) -> dict[str, Any]:
        """
        Fetch scores and aggregate by name.
        Uses GET /api/public/scores
        """
        if not self._available:
            return {"error": "Langfuse not configured", "data": []}

        params: dict[str, Any] = {"limit": limit}
        if from_date:
            params["fromTimestamp"] = from_date
        if to_date:
            params["toTimestamp"] = to_date

        try:
            result = await self._get("/scores", params)
            scores = result.get("data", [])

            # Aggregate by score name
            by_name: dict[str, list] = {}
            for s in scores:
                name = s.get("name", "unknown")
                by_name.setdefault(name, []).append(s)

            summary = {}
            for name, score_list in by_name.items():
                values = [s.get("value") for s in score_list if s.get("value") is not None]
                numeric_values = [v for v in values if isinstance(v, (int, float))]

                entry: dict[str, Any] = {
                    "count": len(score_list),
                    "data_type": score_list[0].get("dataType", "NUMERIC") if score_list else "UNKNOWN",
                }

                if numeric_values:
                    entry["avg"] = round(sum(numeric_values) / len(numeric_values), 3)
                    entry["min"] = round(min(numeric_values), 3)
                    entry["max"] = round(max(numeric_values), 3)
                else:
                    # Categorical — count by value
                    val_counts: dict[str, int] = {}
                    for v in values:
                        val_counts[str(v)] = val_counts.get(str(v), 0) + 1
                    entry["distribution"] = val_counts

                summary[name] = entry

            logger.info("📊 Langfuse scores: %d scores, %d types", len(scores), len(summary))
            return {
                "data": summary,
                "total_scores": len(scores),
                "score_types": list(summary.keys()),
            }
        except Exception as e:
            logger.error("❌ Langfuse scores error: %s", e)
            return {"error": str(e), "data": {}}

    # ─── Sessions ────────────────────────────────────────────────────

    async def get_sessions_summary(self, limit: int = 50) -> dict[str, Any]:
        """
        Fetch recent sessions.
        Uses GET /api/public/sessions
        """
        if not self._available:
            return {"error": "Langfuse not configured", "data": []}

        try:
            result = await self._get("/sessions", {"limit": limit})
            sessions = result.get("data", [])

            simplified = []
            for s in sessions:
                simplified.append({
                    "id": s.get("id", "")[:20],
                    "createdAt": s.get("createdAt", ""),
                    "traceCount": len(s.get("traces", [])) if isinstance(s.get("traces"), list) else 0,
                })

            logger.info("📊 Langfuse sessions: %d", len(simplified))
            return {
                "data": simplified,
                "total_sessions": len(simplified),
            }
        except Exception as e:
            logger.error("❌ Langfuse sessions error: %s", e)
            return {"error": str(e), "data": []}
