# import json
# from pathlib import Path
# from typing import Dict, List, Optional

# class QuizI18n:
#     """Handles internationalization for the quiz plugin"""
    
#     def __init__(self, language: str = 'en', custom_synonyms: Optional[Dict] = None):
#         self.language = language
#         self.fallback_language = 'en'
#         self.custom_synonyms = custom_synonyms or {}
        
#         self.i18n_dir = Path(__file__).parent / 'i18n'
#         self.translations = self._load_translations()
#         self.fallback = self._load_fallback()
#         self.quiz_type_map = self._build_quiz_type_map()
    
#     def _load_translations(self) -> Dict:
#         translation_file = self.i18n_dir / f'{self.language}.json'
        
#         if not translation_file.exists():
#             print(f"⚠️  Translation file not found: {translation_file}")
#             print(f"   Falling back to {self.fallback_language}")
#             return {}
        
#         with open(translation_file, 'r', encoding='utf-8') as f:
#             return json.load(f)
    
#     def _load_fallback(self) -> Dict:
#         fallback_file = self.i18n_dir / f'{self.fallback_language}.json'
        
#         with open(fallback_file, 'r', encoding='utf-8') as f:
#             return json.load(f)
    
#     def _build_quiz_type_map(self) -> Dict[str, str]:
#         mapping = {}
        
#         quiz_types = self.translations.get('quiz_types', self.fallback.get('quiz_types', {}))
        
#         for quiz_type, data in quiz_types.items():
#             for synonym in data.get('synonyms', []):
#                 if synonym in mapping:
#                     print(f"⚠️  Synonym conflict: '{synonym}' already maps to '{mapping[synonym]}'")
#                 else:
#                     mapping[synonym.lower()] = quiz_type
            
#             custom = self.custom_synonyms.get(quiz_type, {}).get('synonyms', '')
#             if custom:
#                 custom_list = [s.strip() for s in custom.split(',') if s.strip()]
#                 for synonym in custom_list:
#                     synonym_lower = synonym.lower()
#                     if synonym_lower in mapping:
#                         print(f"⚠️  Custom synonym '{synonym}' conflicts with existing mapping")
#                         print(f"   Skipping to avoid ambiguity")
#                     else:
#                         mapping[synonym_lower] = quiz_type
#                         print(f"✅ Added custom synonym: '{synonym}' -> '{quiz_type}'")
        
#         return mapping
    
#     def get_quiz_type(self, synonym: str) -> Optional[str]:
#         return self.quiz_type_map.get(synonym.lower())
    
#     def get_quiz_synonyms(self, quiz_type: str) -> List[str]:
#         quiz_types = self.translations.get('quiz_types', self.fallback.get('quiz_types', {}))
#         return quiz_types.get(quiz_type, {}).get('synonyms', [])
    
#     def t(self, key: str, fallback: str = '') -> str:
#         keys = key.split('.')
        
#         value = self.translations
#         for k in keys:
#             if isinstance(value, dict):
#                 value = value.get(k)
#             else:
#                 value = None
#                 break
        
#         if value is not None:
#             return str(value)
        
#         value = self.fallback
#         for k in keys:
#             if isinstance(value, dict):
#                 value = value.get(k)
#             else:
#                 value = None
#                 break
        
#         if value is not None:
#             return str(value)
        
#         return fallback or key
    
#     def get_all_quiz_type_synonyms(self) -> List[str]:
#         return list(self.quiz_type_map.keys())

# ==========================================================================================================================
# ==========================================================================================================================
# ==========================================================================================================================

import json
from pathlib import Path
from typing import Any, Dict, List, Optional, Tuple


class QuizI18n:
    """Handles internationalization for the quiz plugin"""

    def __init__(self, language: str = 'en', custom_synonyms: Optional[Dict] = None):
        self.language = language
        self.fallback_language = 'en'
        self.custom_synonyms = custom_synonyms or {}
        self.i18n_dir = Path(__file__).parent / 'i18n'
        self.translations = self._load_translations()
        self.fallback = self._load_fallback()
        self.quiz_type_map = self._build_quiz_type_map()

        # Build resolution maps for config keys and values
        self._config_key_map: Dict[str, str] = {}   # synonym → canonical key
        self._config_val_map: Dict[str, Dict[str, str]] = {}  # canonical_key → {synonym → canonical_value}
        self._build_config_maps()

    # ─────────────────────────────────────────────────────────────────────────
    # Translation loading
    # ─────────────────────────────────────────────────────────────────────────

    def _load_translations(self) -> Dict:
        translation_file = self.i18n_dir / f'{self.language}.json'
        if not translation_file.exists():
            print(f"⚠️  Translation file not found: {translation_file}")
            print(f"   Falling back to {self.fallback_language}")
            return {}
        with open(translation_file, 'r', encoding='utf-8') as f:
            return json.load(f)

    def _load_fallback(self) -> Dict:
        fallback_file = self.i18n_dir / f'{self.fallback_language}.json'
        with open(fallback_file, 'r', encoding='utf-8') as f:
            return json.load(f)

    # ─────────────────────────────────────────────────────────────────────────
    # Quiz type synonym map
    # ─────────────────────────────────────────────────────────────────────────

    def _build_quiz_type_map(self) -> Dict[str, str]:
        mapping = {}
        quiz_types = self.translations.get('quiz_types', self.fallback.get('quiz_types', {}))
        for quiz_type, data in quiz_types.items():
            for synonym in data.get('synonyms', []):
                if synonym in mapping:
                    print(f"⚠️  Synonym conflict: '{synonym}' already maps to '{mapping[synonym]}'")
                else:
                    mapping[synonym.lower()] = quiz_type

            custom = self.custom_synonyms.get(quiz_type, {}).get('synonyms', '')
            if custom:
                custom_list = [s.strip() for s in custom.split(',') if s.strip()]
                for synonym in custom_list:
                    synonym_lower = synonym.lower()
                    if synonym_lower in mapping:
                        print(f"⚠️  Custom synonym '{synonym}' conflicts with existing mapping")
                        print(f"   Skipping to avoid ambiguity")
                    else:
                        mapping[synonym_lower] = quiz_type
                        print(f"✅ Added custom synonym: '{synonym}' -> '{quiz_type}'")
        return mapping

    # ─────────────────────────────────────────────────────────────────────────
    # Config key/value resolution maps
    # ─────────────────────────────────────────────────────────────────────────

    # Canonical config keys that take a restricted set of values
    # (other keys like min_score, default_false accept arbitrary numbers)
    _VALUE_KEYS = {
        'scoring_mode':    ('all_or_nothing', 'some_or_nothing', 'proportional'),
        'show_correction': ('yes', 'no', 'on_demand'),
        'min_score':       ('none',),   # only "none" is a symbolic value; numbers pass through
        'save_answers':    ('yes', 'no'),
        'clamp_max_score': ('yes', 'no'),
        'randomize_answers':   ('yes', 'no'),
        'randomize_questions': ('yes', 'no'),
        'compare_answers':     ('yes', 'no'),
        'case_sensitive':      ('yes', 'no'),
        'ignore_spaces':       ('yes', 'no'),
        'ignore_accents':      ('yes', 'no'),
        'strip_spaces':        ('yes', 'no'),
    }

    def _build_config_maps(self) -> None:
        """
        Build two lookup dicts from en.json (always) + current lang JSON (if different):

        _config_key_map : { synonym_lower → canonical_key }
            e.g. "mode_evaluation" → "scoring_mode"
                 "scoring_mode"   → "scoring_mode"   (identity, from en.json)

        _config_val_map : { canonical_key → { synonym_lower → canonical_value } }
            e.g. "scoring_mode" → { "proportionnel" → "proportional",
                                     "proportional"  → "proportional", ... }
        """
        key_map: Dict[str, str] = {}
        val_map: Dict[str, Dict[str, str]] = {}

        # Merge en.json (fallback) + current lang (overrides/adds)
        sources: List[Dict] = [self.fallback]
        if self.language != self.fallback_language and self.translations:
            sources.append(self.translations)

        for src in sources:
            cfg = src.get('quiz_configs', {})
            for canonical_key, synonyms in cfg.items():
                if not isinstance(synonyms, list):
                    continue

                # Determine if this entry is a canonical config KEY or a canonical config VALUE
                # Convention: if the key is one of the known canonical keys → it's a key entry
                #             if the key is one of the known canonical values → it's a value entry
                # (They are all present as top-level entries in quiz_configs)

                # Register as config key synonyms
                for syn in synonyms:
                    key_map[syn.lower()] = canonical_key

                # Also register as value synonyms for keys that accept this value
                for config_key, valid_values in self._VALUE_KEYS.items():
                    if canonical_key in valid_values:
                        if config_key not in val_map:
                            val_map[config_key] = {}
                        for syn in synonyms:
                            val_map[config_key][syn.lower()] = canonical_key

        self._config_key_map = key_map
        self._config_val_map = val_map

    # ─────────────────────────────────────────────────────────────────────────
    # Public resolution API
    # ─────────────────────────────────────────────────────────────────────────

    def resolve_config_key(self, raw_key: str) -> str:
        """
        Resolve a (possibly translated) config key to its canonical English name.

        Examples:
            "mode_evaluation"  → "scoring_mode"   (fr)
            "scoring_mode"     → "scoring_mode"   (en, identity)
            "unknown_key"      → "unknown_key"    (passthrough — not our concern)
        """
        return self._config_key_map.get(raw_key.lower(), raw_key)

    def resolve_config_value(self, canonical_key: str, raw_value: Any) -> Any:
        """
        Resolve a (possibly translated) config value to its canonical English value.
        Only string values are translated; numbers/booleans/None pass through.

        Examples (fr):
            resolve_config_value("scoring_mode", "proportionnel") → "proportional"
            resolve_config_value("show_correction", "oui")        → "yes"
            resolve_config_value("min_score", "aucun")            → "none"
            resolve_config_value("min_score", -1)                 → -1    (number, passthrough)
            resolve_config_value("unknown", "foo")                → "foo" (passthrough)
        """
        if not isinstance(raw_value, str):
            return raw_value

        val_lookup = self._config_val_map.get(canonical_key, {})
        return val_lookup.get(raw_value.lower(), raw_value)

    def normalize_config_dict(self, raw: Dict[str, Any]) -> Dict[str, Any]:
        """
        Normalize an entire config dict: resolve all keys and values.

        Input (fr):
            { "mode_evaluation": "proportionnel", "afficher_correction": "oui" }
        Output:
            { "scoring_mode": "proportional", "show_correction": "yes" }

        Nested dicts (e.g. losing_mode) are passed through as-is.
        """
        out: Dict[str, Any] = {}
        for raw_key, raw_val in raw.items():
            canon_key = self.resolve_config_key(raw_key)
            if isinstance(raw_val, dict):
                # Recurse for nested dicts (e.g. losing_mode sub-dict)
                # But only shallow-normalize the nested keys — values inside
                # losing_mode are answer texts or scores, not config values.
                out[canon_key] = raw_val
            else:
                canon_val = self.resolve_config_value(canon_key, raw_val)
                out[canon_key] = canon_val
        return out

    # ─────────────────────────────────────────────────────────────────────────
    # Keywords for parser (preamble / question / answers section headers)
    # ─────────────────────────────────────────────────────────────────────────

    def get_parser_keywords(self) -> Dict[str, List[str]]:
        """
        Return merged keyword lists for parser use.
        Always includes English keywords; adds current-lang keywords if different.
        """
        en_cfg = self.fallback.get('quiz_configs', {})
        lang_cfg = self.translations.get('quiz_configs', {}) if self.language != self.fallback_language else {}

        def merge_lists(key: str) -> List[str]:
            en_list = en_cfg.get(key, [])
            lang_list = lang_cfg.get(key, [])
            combined = list(en_list)
            for item in lang_list:
                if item not in combined:
                    combined.append(item)
            return combined

        return {
            'preamble':  merge_lists('preamble_keywords'),
            'question':  merge_lists('question_keywords'),
            'answers':   merge_lists('answers_keywords'),
        }

    # ─────────────────────────────────────────────────────────────────────────
    # Quiz type helpers (unchanged from original)
    # ─────────────────────────────────────────────────────────────────────────

    def get_quiz_type(self, synonym: str) -> Optional[str]:
        return self.quiz_type_map.get(synonym.lower())

    def get_quiz_synonyms(self, quiz_type: str) -> List[str]:
        quiz_types = self.translations.get('quiz_types', self.fallback.get('quiz_types', {}))
        return quiz_types.get(quiz_type, {}).get('synonyms', [])

    def get_all_quiz_type_synonyms(self) -> List[str]:
        return list(self.quiz_type_map.keys())

    # ─────────────────────────────────────────────────────────────────────────
    # Translation helper
    # ─────────────────────────────────────────────────────────────────────────

    def t(self, key: str, fallback: str = '') -> str:
        keys = key.split('.')
        value = self.translations
        for k in keys:
            if isinstance(value, dict):
                value = value.get(k)
            else:
                value = None
                break
        if value is not None:
            return str(value)

        value = self.fallback
        for k in keys:
            if isinstance(value, dict):
                value = value.get(k)
            else:
                value = None
                break
        if value is not None:
            return str(value)

        return fallback or key


