"""OpenAI adapter: Chat Completions with json_schema response_format (strict off: Pydantic validates)."""
from __future__ import annotations
import time

from pydantic import ValidationError

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


class OpenAIProvider:
    name = "openai"

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

    def structured(self, *, model, system, parts, schema, max_tokens=8000, cache_system=True) -> Result:
        # OpenAI caches long identical prefixes automatically; cache_system needs no flag.
        content = []
        for p in parts:
            if isinstance(p, ImagePart):
                content.append({"type": "image_url",
                                "image_url": {"url": f"data:{p.media_type};base64,{p.b64()}", "detail": "high"}})
            else:
                content.append({"type": "text", "text": p.text})
        t0 = time.monotonic()
        try:
            resp = self.client.chat.completions.create(
                model=model, max_completion_tokens=max_tokens,
                messages=[{"role": "system", "content": system}, {"role": "user", "content": content}],
                response_format={"type": "json_schema", "json_schema": {
                    "name": schema_name(schema), "schema": schema.model_json_schema(), "strict": False}})
        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
        raw = resp.choices[0].message.content or ""
        try:
            parsed = schema.model_validate_json(raw)
        except ValidationError as e:
            raise SchemaError(str(e), raw) from e
        u = resp.usage
        cached = getattr(getattr(u, "prompt_tokens_details", None), "cached_tokens", 0) or 0
        return Result(parsed=parsed, raw_text=raw, provider=self.name, model=model,
                      tokens_in=u.prompt_tokens, tokens_out=u.completion_tokens, cached_tokens=cached,
                      latency_ms=int((time.monotonic() - t0) * 1000))
