"""Per-session SQLite trace database — read layer for Mixer Studio.

All connections are read-only and short-lived (open → query → close).
"""

from __future__ import annotations

import sqlite3
from dataclasses import dataclass, field
from pathlib import Path


@dataclass
class TraceEventRow:
    id: int = 0
    call_id: str = ""
    agent_name: str = ""
    event_type: str = ""
    timestamp_utc: str = ""
    model: str = ""
    provider: str = ""
    mode: str = ""
    session_id: str = ""
    depth: int = 0
    duration_secs: float | None = None
    cost_usd: float | None = None
    status: str = ""
    error_message: str = ""
    is_resume: bool = False
    created_at: str = ""


@dataclass
class TraceDbSummary:
    total_calls: int = 0
    total_duration_seconds: float = 0.0
    total_cost_usd: float = 0.0
    agents: dict[str, int] = field(default_factory=dict)
    events: list[TraceEventRow] = field(default_factory=list)


def _db_path(session_folder: Path) -> Path:
    return session_folder / "logs" / "trace.db"


def has_trace_db(session_folder: Path) -> bool:
    return _db_path(session_folder).is_file()


def _connect_ro(session_folder: Path) -> sqlite3.Connection:
    """Open a read-only connection.  Caller must close it."""
    db = _db_path(session_folder)
    uri = f"file:{db}?mode=ro"
    conn = sqlite3.connect(uri, uri=True, timeout=3)
    conn.row_factory = sqlite3.Row
    return conn


def _row_to_event(row: sqlite3.Row) -> TraceEventRow:
    return TraceEventRow(
        id=row["id"],
        call_id=row["call_id"],
        agent_name=row["agent_name"],
        event_type=row["event_type"],
        timestamp_utc=row["timestamp_utc"],
        model=row["model"],
        provider=row["provider"],
        mode=row["mode"],
        session_id=row["session_id"],
        depth=row["depth"],
        duration_secs=row["duration_secs"],
        cost_usd=row["cost_usd"],
        status=row["status"],
        error_message=row["error_message"],
        is_resume=bool(row["is_resume"]),
        created_at=row["created_at"],
    )


def query_all_events(session_folder: Path) -> list[TraceEventRow]:
    conn = _connect_ro(session_folder)
    try:
        rows = conn.execute("SELECT * FROM trace_events ORDER BY id").fetchall()
        return [_row_to_event(r) for r in rows]
    finally:
        conn.close()


def query_events_after(session_folder: Path, after_id: int) -> list[TraceEventRow]:
    """Return events with id > *after_id*, ordered by id."""
    conn = _connect_ro(session_folder)
    try:
        rows = conn.execute(
            "SELECT * FROM trace_events WHERE id > ? ORDER BY id", (after_id,)
        ).fetchall()
        return [_row_to_event(r) for r in rows]
    finally:
        conn.close()


def query_summary(session_folder: Path) -> TraceDbSummary:
    """Build an aggregate summary from the trace database."""
    conn = _connect_ro(session_folder)
    try:
        rows = conn.execute("SELECT * FROM trace_events ORDER BY id").fetchall()
        events = [_row_to_event(r) for r in rows]

        summary = TraceDbSummary(events=events)
        for ev in events:
            if ev.event_type == "end":
                summary.total_calls += 1
                summary.agents[ev.agent_name] = summary.agents.get(ev.agent_name, 0) + 1
                if ev.duration_secs is not None:
                    summary.total_duration_seconds += ev.duration_secs
                if ev.cost_usd is not None:
                    summary.total_cost_usd += ev.cost_usd
        return summary
    finally:
        conn.close()


def query_max_id(session_folder: Path) -> int:
    conn = _connect_ro(session_folder)
    try:
        row = conn.execute("SELECT COALESCE(MAX(id), 0) FROM trace_events").fetchone()
        return row[0]
    finally:
        conn.close()
