"""Anthropic adapter: forced tool use for structured output; system prompt cached."""
from __future__ import annotations
import json
import time

from pydantic import ValidationError

from .base import ImagePart, ProviderError, Result, SchemaError, TextPart, schema_name


class AnthropicProvider:
    name = "anthropic"

    def __init__(self, api_key: str | None = None):
        import anthropic
        self._sdk = anthropic
        self.client = anthropic.Anthropic(api_key=api_key)

    def structured(self, *, model, system, parts, schema, max_tokens=8000, cache_system=True) -> Result:
        tool = {"name": schema_name(schema), "description": "Return the result.",
                "input_schema": schema.model_json_schema()}
        sys_block = {"type": "text", "text": system}
        if cache_system:
            sys_block["cache_control"] = {"type": "ephemeral"}
        content = []
        for p in parts:
            if isinstance(p, ImagePart):
                content.append({"type": "image", "source": {"type": "base64", "media_type": p.media_type,
                                                            "data": p.b64()}})
            else:
                content.append({"type": "text", "text": p.text})
        t0 = time.monotonic()
        try:
            msg = self.client.messages.create(
                model=model, max_tokens=max_tokens, system=[sys_block],
                messages=[{"role": "user", "content": content}],
                tools=[tool], tool_choice={"type": "tool", "name": tool["name"]})
        except (self._sdk.RateLimitError, self._sdk.APITimeoutError, self._sdk.APIConnectionError,
                self._sdk.InternalServerError) as e:
            raise ProviderError(str(e), retryable=True) from e
        except self._sdk.APIStatusError as e:
            raise ProviderError(str(e), retryable=e.status_code >= 500 or e.status_code == 429) from e
        latency = int((time.monotonic() - t0) * 1000)
        block = next((b for b in msg.content if getattr(b, "type", "") == "tool_use"), None)
        raw = json.dumps(block.input, ensure_ascii=False) if block else ""
        if block is None:
            raise SchemaError("no tool_use block in response", raw)
        try:
            parsed = schema.model_validate(block.input)
        except ValidationError as e:
            raise SchemaError(str(e), raw) from e
        u = msg.usage
        cached = (getattr(u, "cache_read_input_tokens", 0) or 0)
        tokens_in = (u.input_tokens or 0) + cached + (getattr(u, "cache_creation_input_tokens", 0) or 0)
        return Result(parsed=parsed, raw_text=raw, provider=self.name, model=model,
                      tokens_in=tokens_in, tokens_out=u.output_tokens or 0, cached_tokens=cached,
                      latency_ms=latency)
