"""
Pydantic models for the kvict Proxy.

Mirrors the OpenAI /v1/chat/completions request/response format as the
unified interchange format. Other providers translate to/from this.
"""

from __future__ import annotations

from typing import Any, Dict, List, Literal, Optional
from pydantic import BaseModel, Field
import time
import uuid

# ---------------------------------------------------------------------------
# Request models (OpenAI-compatible)
# ---------------------------------------------------------------------------


class ChatMessage(BaseModel):
    role: Literal["system", "user", "assistant", "tool"]
    content: Optional[str] = None
    name: Optional[str] = None
    tool_calls: Optional[List[Dict[str, Any]]] = None
    tool_call_id: Optional[str] = None


class ChatCompletionRequest(BaseModel):
    """Mirrors OpenAI's /v1/chat/completions request body."""

    model: str
    messages: List[ChatMessage]
    temperature: Optional[float] = 1.0
    top_p: Optional[float] = 1.0
    n: Optional[int] = 1
    stream: Optional[bool] = False
    stop: Optional[Any] = None
    max_tokens: Optional[int] = None
    max_completion_tokens: Optional[int] = None
    presence_penalty: Optional[float] = 0.0
    frequency_penalty: Optional[float] = 0.0
    logit_bias: Optional[Dict[str, float]] = None
    user: Optional[str] = None
    # Pass-through for provider-specific fields
    extra: Optional[Dict[str, Any]] = None


# ---------------------------------------------------------------------------
# Response models (OpenAI-compatible)
# ---------------------------------------------------------------------------


class Usage(BaseModel):
    prompt_tokens: int = 0
    completion_tokens: int = 0
    total_tokens: int = 0


class ChoiceMessage(BaseModel):
    role: str = "assistant"
    content: Optional[str] = None
    tool_calls: Optional[List[Dict[str, Any]]] = None


class Choice(BaseModel):
    index: int = 0
    message: ChoiceMessage
    finish_reason: Optional[str] = "stop"


class ChatCompletionResponse(BaseModel):
    """Mirrors OpenAI's /v1/chat/completions response."""

    id: str = Field(default_factory=lambda: f"chatcmpl-{uuid.uuid4().hex[:12]}")
    object: str = "chat.completion"
    created: int = Field(default_factory=lambda: int(time.time()))
    model: str = ""
    choices: List[Choice] = []
    usage: Usage = Field(default_factory=Usage)


# ---------------------------------------------------------------------------
# Streaming models
# ---------------------------------------------------------------------------


class StreamDelta(BaseModel):
    role: Optional[str] = None
    content: Optional[str] = None


class StreamChoice(BaseModel):
    index: int = 0
    delta: StreamDelta
    finish_reason: Optional[str] = None


class ChatCompletionChunk(BaseModel):
    """Single SSE chunk for streaming responses."""

    id: str = ""
    object: str = "chat.completion.chunk"
    created: int = Field(default_factory=lambda: int(time.time()))
    model: str = ""
    choices: List[StreamChoice] = []


# ---------------------------------------------------------------------------
# Savings / metrics models
# ---------------------------------------------------------------------------


class TokenPricing(BaseModel):
    """Per-token pricing for a specific model."""

    input_cost_per_1k: float = 0.0
    output_cost_per_1k: float = 0.0
    cached_input_cost_per_1k: float = 0.0  # Discounted rate for cache hits


class TokenSavings(BaseModel):
    """Savings from a single request."""

    baseline_tokens: int = 0
    actual_tokens: int = 0
    cached_tokens: int = 0
    dollars_saved: float = 0.0
    cache_hit: bool = False


class SavingsSummary(BaseModel):
    """Aggregate savings for dashboard / badge."""

    tokens_saved_total: int = 0
    messages_gained: int = 0
    dollars_saved: float = 0.0
    cache_hit_rate: float = 0.0
    total_requests: int = 0
    cache_hits: int = 0
    cache_misses: int = 0


class SavingsHistoryEntry(BaseModel):
    """One data point in the savings time series."""

    date: str
    tokens_saved: int = 0
    dollars_saved: float = 0.0
    requests: int = 0
    cache_hit_rate: float = 0.0


class UsageByModel(BaseModel):
    """Per-model usage breakdown."""

    model: str
    total_tokens: int = 0
    tokens_saved: int = 0
    dollars_saved: float = 0.0
    requests: int = 0
    cache_hit_rate: float = 0.0
