from __future__ import annotations

from openai import AsyncOpenAI
from ai.base import AIProvider, ClassificationResult
from ai.utils import parse_classification, parse_suggestions


class OpenAIProvider(AIProvider):
    def __init__(
        self,
        api_key: str,
        model: str = "gpt-4o",
        base_url: str | None = None,
        context_chars: int = 8000,
    ):
        self._api_key = api_key or "not-needed"
        self._model = model
        self._base_url = base_url
        self._context_chars = context_chars
        # Singleton: created once in __init__, reused for all calls on this instance.
        # Do NOT recreate per API call — AsyncOpenAI wraps an httpx.AsyncClient
        # that maintains a connection pool; recreating per call destroys pool reuse
        # and forces a new TLS handshake per request (D-07 / RESEARCH.md).
        self._client = AsyncOpenAI(api_key=self._api_key, base_url=self._base_url)

    def _truncate(self, text: str) -> str:
        """D-13 smart truncation: first 60% + last 40% of context window.

        Captures both document introduction and conclusion, which carry the
        most topic signal for long documents.
        """
        if len(text) <= self._context_chars:
            return text
        head_len = int(self._context_chars * 0.6)
        tail_len = self._context_chars - head_len
        return text[:head_len] + "\n[...truncated...]\n" + text[-tail_len:]

    async def classify(
        self,
        document_text: str,
        existing_topics: list[str],
        system_prompt: str,
    ) -> ClassificationResult:
        topics_str = ", ".join(existing_topics) if existing_topics else "(none yet)"
        user_msg = (
            f"Existing topics: [{topics_str}]\n\n"
            f"Document text:\n{self._truncate(document_text)}"
        )
        response = await self._client.chat.completions.create(
            model=self._model,
            max_tokens=1024,
            messages=[
                {"role": "system", "content": system_prompt},
                {"role": "user", "content": user_msg},
            ],
        )
        raw = response.choices[0].message.content or ""
        return parse_classification(raw)

    async def suggest_topics(
        self,
        document_text: str,
        system_prompt: str,
    ) -> list[str]:
        user_msg = (
            "Suggest 3-5 topic names for this document. "
            "Return ONLY valid JSON: {\"suggested_topics\": [\"topic1\", \"topic2\"]}\n\n"
            f"Document text:\n{self._truncate(document_text)}"
        )
        response = await self._client.chat.completions.create(
            model=self._model,
            max_tokens=256,
            messages=[
                {"role": "system", "content": system_prompt},
                {"role": "user", "content": user_msg},
            ],
        )
        raw = response.choices[0].message.content or ""
        return parse_suggestions(raw)

    async def health_check(self) -> bool:
        try:
            await self._client.chat.completions.create(
                model=self._model,
                max_tokens=5,
                messages=[{"role": "user", "content": "ping"}],
            )
            return True
        except Exception:
            return False
