"""LLM 网关统一接口契约（C1 / ARCH §4.1）——snake_case，Pydantic v2。

上层（编排器/Agent）只碰这些类型，永不接触具体厂商字段。Agent 只声明 `tier`，
不传具体 model（不变量 ②）。
"""

from __future__ import annotations

import uuid
from typing import Literal

from pydantic import BaseModel, ConfigDict, Field

Tier = Literal["writer", "analyst", "light"]


class Block(BaseModel):
    """一个 prompt 文本块；`cache=True` 标记缓存断点前的稳定块（ARCH §4.6）。"""

    text: str
    cache: bool = False


class Scope(BaseModel):
    """调用作用域。原型单用户：`user_id` 可固定 stub，`project_id` 可空。"""

    user_id: uuid.UUID
    project_id: uuid.UUID | None = None


class LlmRequest(BaseModel):
    """统一请求。`system` 稳定块在前（断点前），`input` 易变内容在后。"""

    model_config = ConfigDict(arbitrary_types_allowed=True)

    tier: Tier
    input: str | list[Block]
    system: list[Block] = Field(default_factory=list)
    stream: bool = False
    output_schema: type[BaseModel] | None = None
    thinking: bool = False
    max_tokens: int | None = None
    scope: Scope


class Usage(BaseModel):
    """一次调用的用量与成本（落 usage_ledger，ARCH §4.8）。"""

    provider: str
    model: str
    input_tokens: int
    output_tokens: int
    cache_read_tokens: int = 0
    cost_minor: int  # 最小货币单位（如分/cent）
    currency: str


class ServedBy(BaseModel):
    """实际服务方（C1 扩，T5.4）。

    - `fell_back`：是否走了回退链（主模型失败/熔断后由链上后续 provider 服务）。
    - `degraded`：是否发生能力降级（如所选 provider 不支持原生结构化输出，
      改走 instructor JSON-提示路径）。两者仅观测/记账标注，对上层正确性透明。
    """

    provider: str
    model: str
    fell_back: bool = False
    degraded: bool = False


class LlmResponse(BaseModel):
    model_config = ConfigDict(arbitrary_types_allowed=True)

    text: str
    parsed: BaseModel | None = None
    usage: Usage
    served_by: ServedBy


class Delta(BaseModel):
    """流式增量：归一各家 SSE 的统一 token 块。"""

    text: str
