import json
import os
from enum import Enum
from typing import Any, Dict, List, Optional


class SupportedLanguage(Enum):
    EN = "en"
    ES = "es"
    FR = "fr"
    DE = "de"
    IT = "it"
    PT = "pt"
    RU = "ru"
    JA = "ja"
    KO = "ko"
    HI = "hi"
    ID = "id"

    @classmethod
    def from_string(cls, value: str) -> Optional["SupportedLanguage"]:
        for language in cls:
            if language.value == value.lower():
                return language
        return None


class KeyBasedTranslator:
    """
    A simple key-based translator that loads translations from JSON files.
    """

    _translations: Dict[SupportedLanguage, Dict[str, Any]] = {}

    def __init__(self, custom_translations: Optional[Dict[SupportedLanguage, Dict[str, Any]]] = None):
        self.custom_translations = custom_translations

    def get_translations(self, language: SupportedLanguage) -> Dict[str, Any]:
        if self.custom_translations is None or language not in self.custom_translations:
            return self.load_translations(language)

        return self.custom_translations[language]

    @classmethod
    def load_translations(cls, language: SupportedLanguage) -> Dict[str, Any]:
        """
        Load translations for a given language from JSON file.
        """
        if language in cls._translations:
            return cls._translations[language]

        # Try to load from JSON file
        json_path = os.path.join("locales", language.value, "translations.json")

        if os.path.exists(json_path):
            try:
                with open(json_path, "r", encoding="utf-8") as f:
                    translations = json.load(f)
                    cls._translations[language] = translations
                    return translations
            except (json.JSONDecodeError, IOError):
                pass

        # Fallback to empty dict
        cls._translations[language] = {}
        return cls._translations[language]

    def _translate(self, key: str, language: Optional[SupportedLanguage] = None) -> Optional[str]:
        if language is None:
            language = SupportedLanguage.EN

        translations = self.get_translations(language)

        # Support nested keys with dot notation (e.g., "user.profile.name")
        value = translations
        for part in key.split("."):
            if isinstance(value, dict) and part in value:
                value = value[part]
            else:
                return None

        return str(value) if value is not None else None

    def translate(
        self, key: str, language: Optional[SupportedLanguage] = None, default: Optional[str] = None
    ) -> str:
        translation = self._translate(key, language)
        if translation is None and default is not None:
            return default
        if translation is None and language != SupportedLanguage.EN:
            translation = self._translate(key, SupportedLanguage.EN)

        return translation if translation is not None else key


_default_translator = KeyBasedTranslator()


def _t(
    key: Optional[str], language: Optional[SupportedLanguage] = None, default: Optional[str] = None
) -> str:
    """
    Convenience function for translating keys.
    """
    if key is None:
        return ""

    return _default_translator.translate(key, language, default)


def get_language_abbr_from_accept_language(request) -> List[str]:
    """Extract language abbreviations from Accept-Language header."""
    accept_language = getattr(request, "headers", {}).get("accept-language", "")
    if hasattr(request, "headers"):
        accept_language = request.headers.get("accept-language", "")
    else:
        # Fallback for different request types
        accept_language = getattr(request, "accept_language", "")

    language_abbrs = []

    if accept_language:
        # Split by comma to separate different language tags
        language_tags = accept_language.split(",")

        for tag in language_tags:
            # Split by semicolon to remove quality values (e.g., q=0.9)
            language_code = tag.split(";")[0].strip()
            # Extract just the language part (e.g., "en" from "en-US")
            language_abbr = language_code.split("-")[0].lower()
            language_abbrs.append(language_abbr)

    return language_abbrs


def resolve_preferred_language_from_request(
    request, default: SupportedLanguage = SupportedLanguage.EN
) -> SupportedLanguage:
    """Resolve the user's preferred language from Accept-Language header."""
    try:
        abbr_list = get_language_abbr_from_accept_language(request)
    except Exception:
        abbr_list = []

    for abbr in abbr_list:
        lang = SupportedLanguage.from_string(abbr)
        if lang is not None:
            return lang

    return default
