import copy
from typing import Optional

from locked_dict.locked_dict import LockedDict


class Localizer:
    _langs_data: LockedDict[LockedDict[str, str]]
    _default_lang: str
    _allowed_langs: list[str]

    def __init__(self, default_lang: str, allowed_langs: Optional[list[str]]):
        self._langs_data = LockedDict()
        self._default_lang = default_lang

        self._allowed_langs = allowed_langs
        if self._allowed_langs is None:
            self._allowed_langs = list()
            self._allowed_langs.append(self._default_lang)

    def add_lang(self, lang: str):
        if lang not in self._langs_data.keys():
            self._langs_data[lang] = LockedDict()

    def add_domain(self, lang: str, domain: str, domain_data: Optional[dict[str, str]], strip_prefix: bool = False):
        if domain not in self._langs_data[lang].keys():
            self._langs_data[lang][domain] = LockedDict()

        if strip_prefix:
            new_domain_data = dict()
            for key, value in domain_data.items():
                if key.startswith(f"{domain}."):
                    new_domain_data[key[len(f"{domain}."):]] = value
            domain_data = new_domain_data

        self._langs_data[lang][domain].update(domain_data)

    def _localize_internal(self, lang: str, domain: str, key: str, args: list[str] = None) -> Optional[str]:
        if lang not in self._allowed_langs:
            return None

        if lang not in self._langs_data.keys():
            return None

        lang_data = self._langs_data[lang]
        if domain not in lang_data.keys():
            return None

        domain_data = lang_data[domain]
        if key not in domain_data.keys():
            return None

        localized_text = domain_data[key]
        if args is not None:
            for arg_index, arg_value in enumerate(args):
                localized_text = localized_text.replace(f"%{arg_index}", arg_value)

        return localized_text

    def localize(self, lang: str, domain: str, key: str, args: list[str] = None) -> str:
        localized_string = None

        if localized_string is None:
            localized_string = self._localize_internal(lang, domain, key, args)

        if localized_string is None and lang != self._default_lang:
            localized_string = self._localize_internal(self._default_lang, domain, key, args)

        if localized_string is None:
            return domain + "." + key

        return localized_string
