"""
Minimax Provider - Cloud LLM translation via Minimax API (m2.7).

Minimax uses an OpenAI-compatible Chat Completions API.
"""

import threading
import time
from datetime import datetime, timezone
from typing import Any, Dict, List, Optional

import requests
from requests.exceptions import Timeout, ConnectionError as RequestsConnectionError

from core.logging import get_logger
from .base import TranslationProvider
from .schemas import ProviderHealthStatus, TranslationRequest, TranslationResponse

logger = get_logger(__name__)

MINIMAX_RATE_LIMITED = "MINIMAX_RATE_LIMITED"
MINIMAX_INVALID_KEY = "MINIMAX_INVALID_KEY"
MINIMAX_TIMEOUT = "MINIMAX_TIMEOUT"
MINIMAX_SERVICE_ERROR = "MINIMAX_SERVICE_ERROR"

_RETRYABLE_ERRORS = {MINIMAX_RATE_LIMITED, MINIMAX_TIMEOUT, MINIMAX_SERVICE_ERROR}

DEFAULT_TRANSLATION_PROMPT = """You are a professional translator. Translate the following text from {source_lang} to {target_lang}.

Rules:
- Translate ONLY the text, do not add explanations or notes
- Preserve the original formatting, line breaks, and structure
- Maintain the original tone and style
- For technical terms, use the standard translation in the target language
- If the text contains proper nouns or brand names, keep them unchanged unless there's a well-known translation"""


def _get_language_name(code: str) -> str:
    language_names = {
        "en": "English", "fr": "French", "es": "Spanish", "de": "German",
        "it": "Italian", "pt": "Portuguese", "nl": "Dutch", "ru": "Russian",
        "zh": "Chinese", "ja": "Japanese", "ko": "Korean", "ar": "Arabic",
        "hi": "Hindi", "tr": "Turkish", "pl": "Polish", "vi": "Vietnamese",
        "th": "Thai", "uk": "Ukrainian", "cs": "Czech", "sv": "Swedish",
        "ro": "Romanian", "hu": "Hungarian", "el": "Greek", "he": "Hebrew",
    }
    return language_names.get(code.split("-")[0].lower(), code)


class MinimaxProviderError(Exception):
    def __init__(self, code: str, message: str, details: Optional[Dict[str, Any]] = None):
        self.code = code
        self.message = message
        self.details = details or {}
        super().__init__(message)


class MinimaxTranslationProvider(TranslationProvider):
    """
    Minimax translation provider using OpenAI-compatible API.

    Default model: MiniMax-M1 (latest). Also supports m2.7 via env config.
    """

    def __init__(
        self,
        api_key: str,
        model: str = "MiniMax-M1",
        timeout: int = 60,
        max_retries: int = 3,
        retry_delay: float = 1.0,
        base_url: str = "https://api.minimax.chat/v1",
        group_id: str = "",
    ):
        if not api_key or not api_key.strip():
            raise ValueError("Minimax API key cannot be empty")

        self._api_key = api_key
        self._model = model
        self._base_url = base_url.rstrip("/")
        self._group_id = group_id
        self._provider_name = "minimax"
        self._timeout = timeout
        self._max_retries = max_retries
        self._retry_delay = retry_delay
        self._health_cache: Dict[str, Any] = {}
        self._health_cache_ttl = 60
        self._health_cache_lock = threading.Lock()

    def _make_api_request(self, text: str, system_prompt: str) -> tuple:
        if not text or not text.strip():
            return text, {}

        url = f"{self._base_url}/chat/completions"
        headers = {
            "Authorization": f"Bearer {self._api_key}",
            "Content-Type": "application/json",
        }
        payload = {
            "model": self._model,
            "messages": [
                {"role": "system", "content": system_prompt},
                {"role": "user", "content": text},
            ],
            "temperature": 0.3,
            "max_tokens": 4096,
        }

        try:
            response = requests.post(url, headers=headers, json=payload, timeout=self._timeout)

            if response.status_code == 401:
                raise MinimaxProviderError(MINIMAX_INVALID_KEY, "Cle API Minimax invalide.")
            if response.status_code == 429:
                raise MinimaxProviderError(MINIMAX_RATE_LIMITED, "Limite de requetes Minimax atteinte.")
            if response.status_code >= 500:
                raise MinimaxProviderError(MINIMAX_SERVICE_ERROR, "Service Minimax temporairement indisponible.")
            if response.status_code != 200:
                raise MinimaxProviderError(MINIMAX_SERVICE_ERROR, f"Erreur Minimax: {response.text[:200]}")

            data = response.json()
            choices = data.get("choices", [])
            if not choices:
                raise MinimaxProviderError(MINIMAX_SERVICE_ERROR, "Reponse Minimax vide")

            content = choices[0].get("message", {}).get("content", "")
            if not content:
                raise MinimaxProviderError(MINIMAX_SERVICE_ERROR, "Reponse Minimax vide")

            return content.strip(), data.get("usage", {})

        except Timeout:
            raise MinimaxProviderError(MINIMAX_TIMEOUT, "Delai d'attente Minimax depasse.")
        except RequestsConnectionError:
            raise MinimaxProviderError(MINIMAX_SERVICE_ERROR, "Service Minimax indisponible.")
        except MinimaxProviderError:
            raise
        except Exception as e:
            raise MinimaxProviderError(MINIMAX_SERVICE_ERROR, f"Erreur Minimax: {str(e)[:100]}")

    def get_name(self) -> str:
        return self._provider_name

    def is_available(self) -> bool:
        try:
            headers = {"Authorization": f"Bearer {self._api_key}"}
            response = requests.get(f"{self._base_url}/models", headers=headers, timeout=5)
            return response.status_code == 200
        except Exception:
            return False

    def translate_text(self, request: TranslationRequest) -> TranslationResponse:
        text = request.text
        target_language = request.target_language
        source_language = request.source_language or "auto"

        if not text or not text.strip():
            return TranslationResponse(translated_text=text, provider_name=self._provider_name, from_cache=False)

        source_lang_name = _get_language_name(source_language)
        target_lang_name = _get_language_name(target_language)
        custom_prompt = request.metadata.get("custom_prompt") if request.metadata else None
        system_prompt = custom_prompt or DEFAULT_TRANSLATION_PROMPT.format(
            source_lang=source_lang_name, target_lang=target_lang_name
        )

        last_error = None
        for attempt in range(self._max_retries + 1):
            try:
                start_time = time.time()
                result, usage = self._make_api_request(text, system_prompt)
                latency = time.time() - start_time

                logger.info("minimax_translation_success",
                    chars=len(text), source_lang=source_language, target_lang=target_language,
                    model=self._model, latency_ms=round(latency * 1000, 2), retries=attempt)

                return TranslationResponse(
                    translated_text=result, provider_name=self._provider_name,
                    from_cache=False, source_language=source_language)

            except MinimaxProviderError as e:
                last_error = e
                if e.code not in _RETRYABLE_ERRORS or attempt >= self._max_retries:
                    break
                delay = self._retry_delay * (2 ** attempt)
                time.sleep(delay)

        return TranslationResponse(
            translated_text=text, provider_name=self._provider_name, from_cache=False,
            error=last_error.message if last_error else "Unknown error",
            error_code=last_error.code if last_error else MINIMAX_SERVICE_ERROR)

    def translate_batch(self, requests: List[TranslationRequest]) -> List[TranslationResponse]:
        return [self.translate_text(req) for req in requests]

    def health_check(self) -> ProviderHealthStatus:
        start_time = time.time()
        try:
            headers = {"Authorization": f"Bearer {self._api_key}"}
            response = requests.get(f"{self._base_url}/models", headers=headers, timeout=5)
            latency_ms = (time.time() - start_time) * 1000
            return ProviderHealthStatus(
                name=self._provider_name, available=response.status_code == 200,
                latency_ms=round(latency_ms, 2), last_check=datetime.now(timezone.utc).isoformat(),
                model=self._model)
        except Exception as e:
            return ProviderHealthStatus(
                name=self._provider_name, available=False,
                latency_ms=round((time.time() - start_time) * 1000, 2),
                error=str(e)[:100], last_check=datetime.now(timezone.utc).isoformat(),
                model=self._model)


_provider_instance: Optional[MinimaxTranslationProvider] = None
_provider_lock = threading.Lock()


def get_minimax_provider() -> MinimaxTranslationProvider:
    global _provider_instance
    if _provider_instance is None:
        with _provider_lock:
            if _provider_instance is None:
                from .config import ProvidersConfig
                _provider_instance = MinimaxTranslationProvider(
                    api_key=ProvidersConfig.MINIMAX_API_KEY,
                    model=ProvidersConfig.MINIMAX_MODEL,
                    timeout=ProvidersConfig.MINIMAX_TIMEOUT,
                    max_retries=ProvidersConfig.MINIMAX_MAX_RETRIES,
                    retry_delay=ProvidersConfig.MINIMAX_RETRY_DELAY,
                    base_url=ProvidersConfig.MINIMAX_BASE_URL,
                    group_id=ProvidersConfig.MINIMAX_GROUP_ID,
                )
    return _provider_instance


def register_minimax_provider():
    from .registry import registry
    provider = get_minimax_provider()
    registry.register("minimax", provider)
    return provider


def reset_minimax_provider():
    global _provider_instance
    with _provider_lock:
        _provider_instance = None
