"""Logger de uso fire-and-forget para LLM e tool calls."""

from __future__ import annotations

import asyncio
import logging
import os
import time
from decimal import Decimal
from typing import Any

from supabase import Client, create_client

logger = logging.getLogger("tecjustica-mcp.usage")

# Precos por 1M tokens (USD) — atualizar conforme OpenRouter
_PRICING: dict[str, dict[str, Decimal]] = {
    "google/gemini-2.5-flash": {
        "input": Decimal("0.15"),
        "output": Decimal("0.60"),
    },
}

_ONE_MILLION = Decimal("1000000")


def _calc_cost(
    model_id: str,
    tokens_prompt: int | None,
    tokens_completion: int | None,
) -> tuple[Decimal, Decimal, Decimal]:
    """Calcula custo USD baseado em tokens e tabela de precos.

    Returns:
        (cost_input, cost_output, cost_total)
    """
    pricing = _PRICING.get(model_id)
    if not pricing or tokens_prompt is None or tokens_completion is None:
        return Decimal("0"), Decimal("0"), Decimal("0")

    cost_input = Decimal(tokens_prompt) * pricing["input"] / _ONE_MILLION
    cost_output = Decimal(tokens_completion) * pricing["output"] / _ONE_MILLION
    return cost_input, cost_output, cost_input + cost_output


def _handle_task_exception(task: asyncio.Task[Any]) -> None:
    """Callback para logar excecoes de tasks em background."""
    if task.cancelled():
        return
    exc = task.exception()
    if exc:
        logger.warning("Usage log insert failed: %s", exc)


class UsageLogger:
    """Logger de uso com inserts fire-and-forget no Supabase."""

    def __init__(self) -> None:
        url = os.getenv("SUPABASE_URL")
        key = os.getenv("SUPABASE_SERVICE_KEY")
        if not url or not key:
            self._client: Client | None = None
            logger.warning("UsageLogger disabled: missing SUPABASE_URL or SUPABASE_SERVICE_KEY")
            return
        self._client = create_client(url, key)

    def log_llm_call(
        self,
        *,
        tool_name: str,
        call_type: str,
        model_id: str,
        model_alias: str | None = None,
        tokens_prompt: int | None = None,
        tokens_completion: int | None = None,
        tokens_total: int | None = None,
        context_chars: int | None = None,
        duration_ms: int | None = None,
        user_id: str | None = None,
        user_email: str | None = None,
        metadata: dict[str, Any] | None = None,
    ) -> None:
        """Loga chamada LLM — fire-and-forget."""
        if not self._client:
            return

        cost_input, cost_output, cost_total = _calc_cost(model_id, tokens_prompt, tokens_completion)

        row: dict[str, Any] = {
            "tool_name": tool_name,
            "call_type": call_type,
            "model_id": model_id,
            "model_alias": model_alias,
            "tokens_prompt": tokens_prompt,
            "tokens_completion": tokens_completion,
            "tokens_total": tokens_total,
            "cost_input_usd": float(cost_input),
            "cost_output_usd": float(cost_output),
            "cost_total_usd": float(cost_total),
            "context_chars": context_chars,
            "duration_ms": duration_ms,
            "user_id": user_id,
            "user_email": user_email,
            "metadata": metadata or {},
        }

        self._fire_and_forget("llm_usage_logs", row)

    def log_tool_call(
        self,
        *,
        tool_name: str,
        duration_ms: int | None = None,
        success: bool = True,
        error_message: str | None = None,
        user_id: str | None = None,
        user_email: str | None = None,
        params: dict[str, Any] | None = None,
        metadata: dict[str, Any] | None = None,
    ) -> None:
        """Loga chamada de tool — fire-and-forget."""
        if not self._client:
            return

        row: dict[str, Any] = {
            "tool_name": tool_name,
            "duration_ms": duration_ms,
            "success": success,
            "error_message": error_message,
            "user_id": user_id,
            "user_email": user_email,
            "params": params or {},
            "metadata": metadata or {},
        }

        self._fire_and_forget("tool_call_logs", row)

    def _fire_and_forget(self, table: str, row: dict[str, Any]) -> None:
        """Insert assincrono que nao bloqueia o event loop."""
        client = self._client
        if not client:
            return

        async def _insert() -> None:
            await asyncio.to_thread(lambda: client.table(table).insert(row).execute())

        try:
            loop = asyncio.get_running_loop()
            task = loop.create_task(_insert())
            task.add_done_callback(_handle_task_exception)
        except RuntimeError:
            # Sem event loop rodando — fallback sincrono (nao deve acontecer)
            try:
                client.table(table).insert(row).execute()
            except Exception:
                logger.warning("Usage log sync insert failed for %s", table)


# --- Singleton ---

_instance: UsageLogger | None = None


def get_usage_logger() -> UsageLogger:
    """Retorna singleton do UsageLogger."""
    global _instance
    if _instance is None:
        _instance = UsageLogger()
    return _instance


def ms_since(start: float) -> int:
    """Converte perf_counter delta em milissegundos."""
    return int((time.perf_counter() - start) * 1000)
