"""适配器接口与中间数据形（ARCH §4.2/§4.4）。

适配器把 `LlmRequest` 翻译成目标厂商请求，并把响应/流/usage 翻译回统一中间形。
"""

from __future__ import annotations

from collections.abc import AsyncIterator
from typing import Protocol, runtime_checkable

from pydantic import BaseModel, ConfigDict

from ..types import LlmRequest

# 瞬时（可退避重试）的 HTTP 状态码判定：429 限流 或 5xx 服务端错误。
_RATE_LIMITED_STATUS = 429
_SERVER_ERROR_MIN_STATUS = 500


def _is_transient_status(status: object) -> bool:
    return isinstance(status, int) and (
        status == _RATE_LIMITED_STATUS or status >= _SERVER_ERROR_MIN_STATUS
    )


def is_transient_by_name(
    exc: Exception, names: frozenset[str], *, extra_codes: bool = False
) -> bool:
    """统一的瞬时错误判定（DRY：三个适配器共用）。

    ① 异常类名命中 `names`（按名匹配，避免硬依赖各厂商 SDK 异常类型）；或
    ② `status_code` 属性是 429/5xx；或
    ③ `extra_codes=True` 时额外检查 `code` 属性是否为 429/5xx（Gemini 用 `exc.code`）。
    """
    if type(exc).__name__ in names:
        return True
    if _is_transient_status(getattr(exc, "status_code", None)):
        return True
    if extra_codes and _is_transient_status(getattr(exc, "code", None)):
        return True
    return False


class Capabilities(BaseModel):
    structured_output: bool = False
    prefix_cache: bool = False
    thinking: bool = False


class ProviderUsage(BaseModel):
    input_tokens: int
    output_tokens: int
    cache_read_tokens: int = 0


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

    text: str
    usage: ProviderUsage
    parsed: BaseModel | None = None  # output_schema 命中时的结构化结果（§4.4）


class StreamChunk(BaseModel):
    """流式块：文本增量（usage=None），或末尾用量块（text=""）。"""

    text: str = ""
    usage: ProviderUsage | None = None


@runtime_checkable
class ProviderAdapter(Protocol):
    provider: str

    def capabilities(self) -> Capabilities: ...

    async def complete(self, req: LlmRequest, model: str) -> ProviderResult: ...

    def stream(self, req: LlmRequest, model: str) -> AsyncIterator[StreamChunk]: ...
