# -*- coding: utf-8 -*-
"""
Translator - JSON-based i18n for the EMDS QGIS plugin.

Adapted from the plugin_wizard sample. Supported languages: 'en', 'es'.
Adding 'de' / 'pt' is a one-line change to _SUPPORTED plus a JSON file.

Behavior:
  - Active language is auto-detected from QGIS locale on first import.
  - If the user has previously chosen a language via the dock picker, that
    choice is read from QSettings and overrides the auto-detection.
  - Calling set_language() persists the new choice to QSettings and notifies
    any registered listeners so they can refresh their UI.

Usage:
    from .translator import tr, set_language, add_listener

    title = tr('create_workspace.window_title')
    msg = tr('dock.new_project_duplicate', name='Foo')
    set_language('es')
    add_listener(self.retranslateUi)
"""

import json
import os
from typing import Callable, List

_TRANSLATIONS_DIR = os.path.join(os.path.dirname(__file__), 'translations')
_SUPPORTED = ('en', 'es', 'de', 'pt')
_DEFAULT = 'en'
_SETTINGS_KEY = 'EMDS/language'


class _Translator:

    def __init__(self):
        self._data: dict = {}
        self._fallback_data: dict = {}
        self._lang: str = _DEFAULT
        self._listeners: List[Callable[[], None]] = []
        self._fallback_data = self._read_json(_DEFAULT)
        self.load(self._initial_language())

    @staticmethod
    def _read_json(lang: str) -> dict:
        path = os.path.join(_TRANSLATIONS_DIR, f'{lang}.json')
        try:
            with open(path, 'r', encoding='utf-8') as fh:
                return json.load(fh)
        except (FileNotFoundError, json.JSONDecodeError):
            return {}

    @staticmethod
    def _initial_language() -> str:
        """Resolve initial language: persisted user choice > QGIS locale > default."""
        try:
            from qgis.PyQt.QtCore import QSettings
            stored = QSettings().value(_SETTINGS_KEY, '', type=str)
            if stored and stored in _SUPPORTED:
                return stored
        except Exception:
            pass
        try:
            from qgis.core import QgsSettings
            locale = QgsSettings().value("locale/userLocale", "en_US")
            lang = str(locale)[:2].lower()
            return lang if lang in _SUPPORTED else _DEFAULT
        except Exception:
            return _DEFAULT

    def load(self, lang: str):
        if lang not in _SUPPORTED:
            lang = _DEFAULT
        self._data = self._read_json(lang)
        self._lang = lang

    @staticmethod
    def _resolve(data: dict, key: str) -> str:
        node = data
        for part in key.split('.'):
            node = node.get(part, '') if isinstance(node, dict) else ''
        return node if isinstance(node, str) else ''

    def t(self, key: str, **kwargs) -> str:
        # Look in the active language first, then fall back to English so
        # partially-translated catalogs don't leak raw keys into the UI.
        text = self._resolve(self._data, key)
        if not text and self._lang != _DEFAULT:
            text = self._resolve(self._fallback_data, key)
        if kwargs:
            try:
                text = text.format(**kwargs)
            except (KeyError, ValueError):
                pass
        return text or key

    def set_language(self, lang: str):
        if lang == self._lang:
            return
        self.load(lang)
        try:
            from qgis.PyQt.QtCore import QSettings
            QSettings().setValue(_SETTINGS_KEY, self._lang)
        except Exception:
            pass
        self._notify()

    def add_listener(self, callback: Callable[[], None]):
        if callback not in self._listeners:
            self._listeners.append(callback)

    def remove_listener(self, callback: Callable[[], None]):
        if callback in self._listeners:
            self._listeners.remove(callback)

    def _notify(self):
        for cb in list(self._listeners):
            try:
                cb()
            except Exception:
                pass


_translator = _Translator()


def tr(key: str, **kwargs) -> str:
    return _translator.t(key, **kwargs)


def set_language(lang: str):
    _translator.set_language(lang)


def get_language() -> str:
    return _translator._lang


def supported_languages():
    return _SUPPORTED


def add_listener(callback: Callable[[], None]):
    _translator.add_listener(callback)


def remove_listener(callback: Callable[[], None]):
    _translator.remove_listener(callback)
