"""DeepSeek OpenAI-compatible provider adapter."""
from __future__ import annotations

import json
import logging
import os
import re
import urllib.error
import urllib.request
from typing import Any

from ..router_config import RouterProfileConfig
from .base_adapter import BaseProviderAdapter, ErrorCategory, ErrorClassification

logger = logging.getLogger("hermes.router.adapter.deepseek")

DEFAULT_DEEPSEEK_BASE_URL = "https://api.deepseek.com/v1"
DEFAULT_DEEPSEEK_MODELS = ["deepseek-chat", "deepseek-reasoner"]


class DeepSeekResponsesAdapter(BaseProviderAdapter):
    """Adapter for DeepSeek's OpenAI-compatible chat completions API."""

    def _resolve_api_key(self, profile: RouterProfileConfig) -> str | None:
        key = profile.auth_config.get("api_key") or profile.auth_config.get("token")
        if key:
            return str(key)

        suffix = profile.profile_id.upper().replace("-", "_")
        for candidate in (f"DEEPSEEK_API_KEY_{suffix}", "DEEPSEEK_API_KEY"):
            value = os.environ.get(candidate, "").strip()
            if value:
                return value
        return None

    def invoke(self, profile: RouterProfileConfig, request: dict[str, Any]) -> dict[str, Any]:
        api_key = self._resolve_api_key(profile)
        if not api_key:
            raise RuntimeError(f"No API key found for DeepSeek profile '{profile.profile_id}'")

        base_url = (
            profile.custom_base_url
            or os.environ.get("DEEPSEEK_BASE_URL", DEFAULT_DEEPSEEK_BASE_URL)
        ).rstrip("/")

        model = request.get("model", "")
        if not model or model == "default":
            model = profile.preferred_models[0] if profile.preferred_models else "deepseek-chat"

        payload: dict[str, Any] = {
            "model": model,
            "messages": request.get("messages", []),
            "temperature": request.get("temperature", 0.7),
        }
        if request.get("tools"):
            payload["tools"] = request["tools"]
        if "tool_choice" in request:
            payload["tool_choice"] = request["tool_choice"]
        if "response_format" in request:
            payload["response_format"] = request["response_format"]

        req = urllib.request.Request(
            f"{base_url}/chat/completions",
            data=json.dumps(payload).encode("utf-8"),
            headers={
                "Content-Type": "application/json",
                "Authorization": f"Bearer {api_key}",
                "User-Agent": "hermes-router/1.0",
            },
            method="POST",
        )

        try:
            with urllib.request.urlopen(req, timeout=120) as resp:
                return json.loads(resp.read().decode("utf-8", errors="replace"))
        except urllib.error.HTTPError as http_err:
            raw_err = http_err.read().decode("utf-8", errors="replace")
            try:
                err_msg = json.loads(raw_err).get("error", {}).get("message", raw_err)
            except Exception:
                err_msg = raw_err
            raise RuntimeError(f"DeepSeek API Error ({http_err.code}): {err_msg}") from http_err
        except Exception as exc:
            raise RuntimeError(f"DeepSeek Transport Error: {exc}") from exc

    def health_check(self, profile: RouterProfileConfig) -> bool:
        return self._resolve_api_key(profile) is not None

    def discover_models(self, profile: RouterProfileConfig) -> list[str]:
        return list(profile.preferred_models or DEFAULT_DEEPSEEK_MODELS)

    def classify_error(
        self,
        exc: Exception,
        response_data: dict[str, Any] | None = None,
    ) -> ErrorClassification:
        err_msg = str(exc)
        err_lower = err_msg.lower()

        # Rate limits first: a 429 body routinely contains the word "limit",
        # which would otherwise be swallowed by the quota branch below.
        if "429" in err_lower or "rate limit" in err_lower or "too many requests" in err_lower:
            return ErrorClassification(
                category=ErrorCategory.RATE_LIMITED,
                message=err_msg,
                retry_delay_seconds=60,
            )

        if any(k in err_lower for k in ("quota", "insufficient balance", "insufficient_quota", "arrears")):
            reset_sec = 1800
            m_hr = re.search(r"(\d+)\s*(?:hours?|h\b)", err_lower)
            m_min = re.search(r"(\d+)\s*(?:minutes?|m\b)", err_lower)
            if m_hr:
                reset_sec = int(m_hr.group(1)) * 3600
            elif m_min:
                reset_sec = int(m_min.group(1)) * 60
            return ErrorClassification(
                category=ErrorCategory.QUOTA_EXHAUSTED,
                message=err_msg,
                reset_duration_seconds=reset_sec,
            )

        if any(k in err_lower for k in ("401", "403", "unauthorized", "invalid api key", "authentication")):
            return ErrorClassification(category=ErrorCategory.AUTH_REQUIRED, message=err_msg)

        if any(k in err_lower for k in ("timeout", "502", "503", "504", "gateway", "econnreset")):
            return ErrorClassification(
                category=ErrorCategory.TRANSIENT,
                message=err_msg,
                retry_delay_seconds=5,
            )

        return ErrorClassification(category=ErrorCategory.FATAL, message=err_msg)
