"""DeepL translation backend for pretok."""

from __future__ import annotations

import logging
from typing import TYPE_CHECKING

from pretok.translation.base import BaseTranslator, TranslationError, TranslationResult

if TYPE_CHECKING:
    from collections.abc import Sequence

    from pretok.config import DeepLTranslatorConfig

logger = logging.getLogger(__name__)

# DeepL uses specific language codes that differ from ISO 639-1
# Map ISO 639-1 → DeepL language codes
DEEPL_LANGUAGE_MAP: dict[str, str] = {
    "en": "EN-US",
    "pt": "PT-BR",
    "zh": "ZH-HANS",
}

# DeepL supported target languages (subset)
DEEPL_SUPPORTED_TARGETS: set[str] = {
    "BG", "CS", "DA", "DE", "EL", "EN-GB", "EN-US", "ES", "ET", "FI",
    "FR", "HU", "ID", "IT", "JA", "KO", "LT", "LV", "NB", "NL",
    "PL", "PT-BR", "PT-PT", "RO", "RU", "SK", "SL", "SV", "TR",
    "UK", "ZH-HANS", "ZH-HANT", "AR",
}


class DeepLTranslator(BaseTranslator):
    """Translator using DeepL API.

    Requires the ``deepl`` package::

        pip install pretok[deepl]

    Example:
        >>> from pretok.config import DeepLTranslatorConfig
        >>> config = DeepLTranslatorConfig(api_key="your-key")
        >>> translator = DeepLTranslator(config)
        >>> result = translator.translate("Hello", "de")
        >>> result.translated_text
        'Hallo'
    """

    def __init__(self, config: DeepLTranslatorConfig) -> None:
        """Initialize DeepL translator.

        Args:
            config: DeepL translator configuration

        Raises:
            ImportError: If deepl package is not installed
            TranslationError: If API key is not provided
        """
        try:
            import deepl
        except ImportError as e:
            msg = "deepl package is required for DeepLTranslator. Install it with: pip install deepl"
            raise ImportError(msg) from e

        self._config = config
        api_key = config.get_api_key()

        if not api_key:
            raise TranslationError(
                "DeepL API key is required. Set it in config or DEEPL_API_KEY env var.",
                translator="deepl",
            )

        server_url = None
        if config.use_free_api:
            server_url = "https://api-free.deepl.com"

        self._translator = deepl.Translator(api_key, server_url=server_url)
        self._formality = config.formality

        logger.info(
            "Initialized DeepLTranslator: free_api=%s, formality=%s",
            config.use_free_api,
            config.formality,
        )

    @property
    def name(self) -> str:
        """Return translator name."""
        return "deepl"

    @property
    def supported_languages(self) -> list[str]:
        """Return supported languages."""
        return []

    def _to_deepl_lang(self, code: str) -> str:
        """Convert ISO 639-1 code to DeepL language code.

        Args:
            code: ISO 639-1 language code

        Returns:
            DeepL language code
        """
        return DEEPL_LANGUAGE_MAP.get(code.lower(), code.upper())

    def translate(
        self,
        text: str,
        target_language: str,
        source_language: str | None = None,
    ) -> TranslationResult:
        """Translate text using DeepL.

        Args:
            text: Text to translate
            target_language: Target language code
            source_language: Source language code (optional)

        Returns:
            TranslationResult with translated text
        """
        if not text or not text.strip():
            return TranslationResult(
                source_text=text,
                translated_text=text,
                source_language=source_language or "unknown",
                target_language=target_language,
                translator=self.name,
            )

        deepl_target = self._to_deepl_lang(target_language)
        deepl_source = self._to_deepl_lang(source_language) if source_language else None

        try:
            kwargs: dict[str, str | None] = {
                "target_lang": deepl_target,
            }
            if deepl_source:
                kwargs["source_lang"] = deepl_source

            if self._formality != "default":
                kwargs["formality"] = self._formality

            result = self._translator.translate_text(text, **kwargs)

            return TranslationResult(
                source_text=text,
                translated_text=result.text,
                source_language=source_language or (result.detected_source_lang or "auto").lower(),
                target_language=target_language,
                translator=self.name,
                metadata={
                    "detected_source_lang": result.detected_source_lang,
                },
            )

        except Exception as e:
            raise TranslationError(
                f"DeepL translation failed: {e}",
                source_text=text,
                source_language=source_language,
                target_language=target_language,
                translator=self.name,
                cause=e,
            ) from e

    def translate_batch(
        self,
        texts: Sequence[str],
        target_language: str,
        source_language: str | None = None,
    ) -> list[TranslationResult]:
        """Translate multiple texts using DeepL.

        DeepL's API natively supports batch translation.
        """
        if not texts:
            return []

        deepl_target = self._to_deepl_lang(target_language)
        deepl_source = self._to_deepl_lang(source_language) if source_language else None

        try:
            kwargs: dict[str, str | list[str] | None] = {
                "target_lang": deepl_target,
            }
            if deepl_source:
                kwargs["source_lang"] = deepl_source

            if self._formality != "default":
                kwargs["formality"] = self._formality

            results_raw = self._translator.translate_text(list(texts), **kwargs)

            # DeepL returns a list when given a list
            if not isinstance(results_raw, list):
                results_raw = [results_raw]

            results = []
            for i, r in enumerate(results_raw):
                results.append(
                    TranslationResult(
                        source_text=texts[i],
                        translated_text=r.text,
                        source_language=source_language or (r.detected_source_lang or "auto").lower(),
                        target_language=target_language,
                        translator=self.name,
                    )
                )
            return results

        except Exception:
            logger.warning("Batch translation failed, falling back to individual translations")
            return [self.translate(text, target_language, source_language) for text in texts]
