import time
from typing import Any, Dict, Optional

import requests
from requests import HTTPError

from synthneura.core.schemas import LLMRawResponse
from synthneura.llm.base import LLMClient

OPENAI_URL = "https://api.openai.com/v1/chat/completions"


class OpenAIClient(LLMClient):
    """
    OpenAI-backed LLM client for extracting structured trial facts.
    """

    def __init__(
        self,
        api_key: str,
        model: str = "gpt-4o-mini",
        *,
        retries: int = 3,
        backoff_seconds: float = 1.0,
    ) -> None:
        """
        Initialize the client with an API key and model name.
        """

        self.api_key = api_key
        self.model = model
        self.retries = retries
        self.backoff_seconds = backoff_seconds

    def _should_retry(self, status_code: Optional[int]) -> bool:
        return status_code in {429, 500, 502, 503, 504}

    def _backoff(self, attempt: int) -> None:
        sleep_for = self.backoff_seconds * (2**attempt)
        time.sleep(sleep_for)

    def extract_endpoints_biomarkers(self, prompt: str) -> LLMRawResponse:
        """
        Call OpenAI chat completions and parse JSON extraction output.
        """

        headers = {
            "Authorization": f"Bearer {self.api_key}",
            "Content-Type": "application/json",
        }
        payload: Dict[str, Any] = {
            "model": self.model,
            "temperature": 0,
            "messages": [
                {
                    "role": "system",
                    "content": (
                        "You extract structured clinical trial facts. "
                        "Return JSON only, no extra text."
                    ),
                },
                {
                    "role": "user",
                    "content": prompt,
                },
            ],
        }
        last_error: Optional[Exception] = None
        for attempt in range(self.retries + 1):
            try:
                response = requests.post(
                    OPENAI_URL, headers=headers, json=payload, timeout=60
                )
                response.raise_for_status()
                data = response.json()
                break
            except HTTPError as exc:
                last_error = exc
                status_code = exc.response.status_code if exc.response else None
                if attempt < self.retries and self._should_retry(status_code):
                    self._backoff(attempt)
                    continue
                raise
            except requests.RequestException as exc:
                last_error = exc
                if attempt < self.retries:
                    self._backoff(attempt)
                    continue
                raise
        if last_error and "data" not in locals():
            raise last_error

        content = data["choices"][0]["message"]["content"]
        return LLMRawResponse(raw_json=content, model=self.model, provider="openai")
