"""Analytics API endpoints — invocation telemetry and cost tracking.

Reads from the tool_invocations table (created by this module) and from
the existing eval_results table for cost/latency analysis.
"""

from __future__ import annotations

import sqlite3
from pathlib import Path

from aiohttp import web

from hatchdx.dashboard.api.eval_api import _get_all_server_eval_dbs

analytics_routes = web.RouteTableDef()

DB_FILENAME = ".hdx/eval_results.db"

# DDL for the invocation telemetry table (created lazily)
_INVOCATIONS_DDL = """
CREATE TABLE IF NOT EXISTS tool_invocations (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    tool TEXT NOT NULL,
    server TEXT NOT NULL,
    timestamp TEXT NOT NULL,
    latency_ms REAL NOT NULL,
    status TEXT NOT NULL,
    error TEXT
);
CREATE INDEX IF NOT EXISTS idx_invocations_tool ON tool_invocations(tool);
CREATE INDEX IF NOT EXISTS idx_invocations_ts ON tool_invocations(timestamp);
"""


def _get_conn() -> sqlite3.Connection | None:
    db_path = Path.cwd() / DB_FILENAME
    if not db_path.exists():
        return None
    conn = sqlite3.connect(str(db_path), timeout=5)
    conn.row_factory = sqlite3.Row
    # Ensure telemetry table exists
    conn.executescript(_INVOCATIONS_DDL)
    return conn


def _get_all_conns(workspace_root: Path | None) -> list[sqlite3.Connection]:
    """Return connections to all server eval DBs (workspace-aware)."""
    conns: list[sqlite3.Connection] = []
    for _name, db_path in _get_all_server_eval_dbs(workspace_root):
        conn = sqlite3.connect(str(db_path), timeout=5)
        conn.row_factory = sqlite3.Row
        conn.executescript(_INVOCATIONS_DDL)
        conns.append(conn)
    return conns


@analytics_routes.get("/api/analytics/invocations")
async def get_invocations(request: web.Request) -> web.Response:
    days = int(request.query.get("days", "30"))
    group_by = request.query.get("group_by", "tool")  # "tool" or "server"
    workspace_root: Path | None = request.app.get("workspace_root")

    conns = _get_all_conns(workspace_root)
    if not conns:
        return web.json_response({"series": []})

    series: list[dict] = []
    for conn in conns:
        try:
            # First try dedicated invocations table
            cursor = conn.execute(
                f"""
                SELECT
                    DATE(timestamp) as date,
                    {group_by} as label,
                    COUNT(*) as count
                FROM tool_invocations
                WHERE timestamp >= datetime('now', ?)
                GROUP BY date, {group_by}
                ORDER BY date
                """,
                (f"-{days} days",),
            )
            rows = cursor.fetchall()

            if not rows:
                # Fall back to eval_results for invocation data
                cursor = conn.execute(
                    """
                    SELECT
                        DATE(timestamp) as date,
                        eval_name as label,
                        COUNT(*) as count
                    FROM eval_results
                    WHERE timestamp >= datetime('now', ?)
                    GROUP BY date, eval_name
                    ORDER BY date
                    """,
                    (f"-{days} days",),
                )
                rows = cursor.fetchall()

            series.extend(
                {"timestamp": row["date"], "label": row["label"], "value": row["count"]}
                for row in rows
            )
        finally:
            conn.close()

    series.sort(key=lambda s: s["timestamp"])
    return web.json_response({"series": series})


@analytics_routes.get("/api/analytics/latency")
async def get_latency(request: web.Request) -> web.Response:
    days = int(request.query.get("days", "30"))
    workspace_root: Path | None = request.app.get("workspace_root")

    conns = _get_all_conns(workspace_root)
    if not conns:
        return web.json_response({"series": []})

    from collections import defaultdict
    by_date: dict[str, list[float]] = defaultdict(list)

    for conn in conns:
        try:
            cursor = conn.execute(
                """
                SELECT
                    DATE(timestamp) as date,
                    latency_ms
                FROM eval_results
                WHERE timestamp >= datetime('now', ?)
                ORDER BY date
                """,
                (f"-{days} days",),
            )
            for row in cursor.fetchall():
                by_date[row["date"]].append(row["latency_ms"])
        finally:
            conn.close()

    series = []
    for date, latencies in sorted(by_date.items()):
        latencies.sort()
        n = len(latencies)
        series.append({
            "timestamp": date,
            "p50": latencies[n // 2] if n > 0 else 0,
            "p95": latencies[int(n * 0.95)] if n > 0 else 0,
            "p99": latencies[int(n * 0.99)] if n > 0 else 0,
        })

    return web.json_response({"series": series})


@analytics_routes.get("/api/analytics/errors")
async def get_errors(request: web.Request) -> web.Response:
    days = int(request.query.get("days", "30"))
    workspace_root: Path | None = request.app.get("workspace_root")

    conns = _get_all_conns(workspace_root)
    if not conns:
        return web.json_response({"series": []})

    series: list[dict] = []
    for conn in conns:
        try:
            cursor = conn.execute(
                """
                SELECT
                    DATE(timestamp) as date,
                    suite_name as label,
                    COUNT(*) as total,
                    SUM(CASE WHEN passed = 0 THEN 1 ELSE 0 END) as errors
                FROM eval_results
                WHERE timestamp >= datetime('now', ?)
                GROUP BY date, suite_name
                ORDER BY date
                """,
                (f"-{days} days",),
            )

            for row in cursor.fetchall():
                total = row["total"]
                errors = row["errors"]
                series.append({
                    "timestamp": row["date"],
                    "label": row["label"],
                    "value": errors / total if total > 0 else 0,
                })
        finally:
            conn.close()

    series.sort(key=lambda s: s["timestamp"])
    return web.json_response({"series": series})


@analytics_routes.get("/api/analytics/cost")
async def get_cost(request: web.Request) -> web.Response:
    # Cost tracking requires agent eval data (not yet available)
    # Return empty for now — will be populated when agent track ships
    return web.json_response({"breakdown": []})
