"""OpenRouter transcription provider adapter."""

from __future__ import annotations

import base64
import logging
from dataclasses import dataclass
from typing import Any

from openrouter import OpenRouter

from transcription.config import Settings, get_settings
from transcription.providers.base import (
    ProviderAuthError,
    ProviderError,
    ProviderResponseError,
    TranscriptionResult,
)

logger = logging.getLogger(__name__)

DEFAULT_OPENROUTER_MODEL = "google/gemini-2.5-flash"


@dataclass(frozen=True)
class OpenRouterRequest:
    """Normalized request payload fields for OpenRouter calls."""

    model: str
    messages: list[dict[str, Any]]
    http_referer: str | None
    x_open_router_title: str | None


class OpenRouterTranscriptionProvider:
    """Adapter that performs image transcription through OpenRouter."""

    def __init__(self, *, settings: Settings | None = None, client: OpenRouter | None = None):
        self._settings = settings or get_settings()
        self._model = self._settings.provider_model or DEFAULT_OPENROUTER_MODEL
        self._client = client or OpenRouter(api_key=self._settings.openrouter_api_key)

    @property
    def model(self) -> str:
        """Return the resolved OpenRouter model slug."""
        return self._model

    def transcribe(self, *, prompt_text: str, image_bytes: bytes, mime_type: str) -> TranscriptionResult:
        """Send prompt + image to OpenRouter and return normalized text output."""
        request = self._build_request(prompt_text=prompt_text, image_bytes=image_bytes, mime_type=mime_type)
        try:
            response = self._client.chat.send(
                messages=request.messages,
                model=request.model,
                http_referer=request.http_referer,
                x_open_router_title=request.x_open_router_title,
            )
        except Exception as exc:  # noqa: BLE001
            message = str(exc).lower()
            if "401" in message or "auth" in message or "api key" in message:
                raise ProviderAuthError("OpenRouter authentication failed") from exc
            raise ProviderError("OpenRouter request failed") from exc

        text = self._extract_text(response)
        model = self._get_optional_attr(response, "model") or self.model
        logger.info("OpenRouter transcription completed using model=%s", model)
        return TranscriptionResult(text=text, provider="openrouter", model=model)

    def _build_request(self, *, prompt_text: str, image_bytes: bytes, mime_type: str) -> OpenRouterRequest:
        image_b64 = base64.b64encode(image_bytes).decode("ascii")
        data_url = f"data:{mime_type};base64,{image_b64}"

        messages: list[dict[str, Any]] = [
            {
                "role": "user",
                "content": [
                    {"type": "text", "text": prompt_text},
                    {"type": "image_url", "image_url": {"url": data_url}},
                ],
            }
        ]

        return OpenRouterRequest(
            model=self.model,
            messages=messages,
            http_referer=self._settings.openrouter_http_referer,
            x_open_router_title=self._settings.openrouter_app_title,
        )

    def _extract_text(self, response: Any) -> str:
        choices = self._get_optional_attr(response, "choices")
        if not choices:
            raise ProviderResponseError("OpenRouter response missing choices")

        first_choice = choices[0]
        message = self._get_optional_attr(first_choice, "message")
        if message is None:
            raise ProviderResponseError("OpenRouter response missing assistant message")

        content = self._get_optional_attr(message, "content")
        text = self._normalize_content(content)
        if not text:
            raise ProviderResponseError("OpenRouter response contained no transcription text")
        return text

    def _normalize_content(self, content: Any) -> str:
        if isinstance(content, str):
            return content.strip()

        if isinstance(content, list):
            parts: list[str] = []
            for item in content:
                text_part = None
                if isinstance(item, dict):
                    text_part = item.get("text")
                else:
                    text_part = self._get_optional_attr(item, "text")

                if isinstance(text_part, str) and text_part.strip():
                    parts.append(text_part.strip())
            return "\n".join(parts).strip()

        return ""

    @staticmethod
    def _get_optional_attr(obj: Any, key: str) -> Any:
        if obj is None:
            return None
        if isinstance(obj, dict):
            return obj.get(key)
        return getattr(obj, key, None)
