"""Buffered usage logger — batches writes to SQLite for performance."""

from __future__ import annotations

import asyncio
import logging
import time
from dataclasses import dataclass, field

from backend.db.connection import get_db

logger = logging.getLogger("ecate.db.usage")

_FLUSH_INTERVAL = 5.0  # seconds
_FLUSH_BATCH_SIZE = 100


@dataclass
class UsageRecord:
    api_key_id: str | None
    model_id: str
    strategy: str | None
    tokens_in: int
    tokens_out: int
    cost_usd: float
    latency_ttfb_ms: float | None
    latency_total_ms: float | None
    # Anthropic prompt caching
    cache_read_tokens: int = 0
    cache_creation_tokens: int = 0
    was_fallback: bool = False
    fallback_from: str | None = None
    timestamp: float = field(default_factory=time.time)


class UsageLogger:
    """Async buffered logger that flushes usage records to SQLite periodically."""

    def __init__(self):
        self._buffer: list[UsageRecord] = []
        self._lock = asyncio.Lock()
        self._task: asyncio.Task | None = None

    async def start(self):
        """Start the background flush loop."""
        self._task = asyncio.create_task(self._flush_loop())

    async def stop(self):
        """Flush remaining records and stop."""
        if self._task:
            self._task.cancel()
            try:
                await self._task
            except asyncio.CancelledError:
                pass
        await self._flush()

    def log(self, record: UsageRecord):
        """Queue a usage record for async writing."""
        self._buffer.append(record)

    async def _flush_loop(self):
        while True:
            await asyncio.sleep(_FLUSH_INTERVAL)
            await self._flush()

    async def _flush(self):
        async with self._lock:
            if not self._buffer:
                return
            batch = self._buffer[:_FLUSH_BATCH_SIZE]
            self._buffer = self._buffer[_FLUSH_BATCH_SIZE:]

        try:
            db = await get_db()
            await db.executemany(
                """INSERT INTO usage_logs
                   (api_key_id, model_id, strategy, tokens_in, tokens_out,
                    cache_read_tokens, cache_creation_tokens,
                    cost_usd, latency_ttfb_ms, latency_total_ms, was_fallback, fallback_from)
                   VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)""",
                [
                    (
                        r.api_key_id, r.model_id, r.strategy,
                        r.tokens_in, r.tokens_out,
                        r.cache_read_tokens, r.cache_creation_tokens,
                        r.cost_usd,
                        r.latency_ttfb_ms, r.latency_total_ms,
                        r.was_fallback, r.fallback_from,
                    )
                    for r in batch
                ],
            )
            await db.commit()
            logger.debug(f"Flushed {len(batch)} usage records")
        except Exception as e:
            logger.error(f"Failed to flush usage logs: {e}")
            # Re-queue failed records
            self._buffer = batch + self._buffer
