# mscp/common_utils/localization.py
"""Localisation glue for `gettext` and YAML.

Wraps `gettext.translation` so the active language can be switched at
runtime, exposes a `localize_string` shortcut, registers a custom
``!localize`` YAML tag that translates scalars at load time, and
provides a `get_supported_languages` helper that enumerates the
language subdirectories under ``config["locales_dir"]``.
"""

# Standard python modules
import gettext
import yaml
from pathlib import Path
from typing import Any

# Local python modules
from .config import config
from .logger_instance import logger
from .file_handling import open_file


# Global variable to store the gettext localization function
_localization_function = gettext.gettext


def setup_gettext_localization(language: str = "en") -> None:
    """
    Configure gettext for localizations.

    Args:
        domain (str): The localization domain (usually "messages")
        localedir (str): Path to the locales directory
        language (str): Language code (e.g., "de", "fr", "es")
    """
    global _localization_function

    domain: str = "messages"
    localedir: str = config["locales_dir"]

    try:
        # Set up the localization
        localization = gettext.translation(
            domain=domain, localedir=localedir, languages=[language], fallback=True
        )
        _localization_function = localization.gettext
        logger.debug(f"Gettext configured for language: {language}, domain: {domain}")

    except Exception as e:
        logger.warning(f"Failed to setup gettext for language {language}: {e}")
        # Fallback to default gettext behavior
        _localization_function = gettext.gettext


def get_localization_function():
    """
    Get the current localization function.

    Returns:
        callable: The current gettext localization function
    """
    return _localization_function


def localize_string(text: str) -> str:
    """
    localize a string using the configured localization function.

    Args:
        text (str): The string to localize

    Returns:
        str: The localized string
    """
    return _localization_function(text)


def localize_constructor(loader, node):
    """
    Custom YAML constructor for !localize tag that uses gettext for localization.

    Args:
        loader: The YAML loader instance
        node: The YAML node containing the localize string

    Returns:
        str: The localized string using the configured gettext function
    """
    value = loader.construct_scalar(node)
    logger.debug(f"attempting to localize with value: {value}")
    return _localization_function(value)


def register_yaml_constructors() -> None:
    """
    Register the !localize YAML constructor with YAML loaders.

    This function should be called once to enable !localize tag support
    in YAML files.
    """
    yaml.add_constructor("!localize", localize_constructor)
    yaml.SafeLoader.add_constructor("!localize", localize_constructor)


def configure_localization_for_yaml(
    language: str | None = None,
) -> None:
    """
    Configure localization and register YAML constructors in one call.

    Args:
        language (str, optional): Language code for localization (e.g., "de", "fr"). If None, uses current gettext config.
        domain (str): localization domain name. Defaults to "messages".
        localedir (str): Path to the locales directory. Defaults to the bundled data/locales.
    """
    logger.debug(f"configure_localization_for_yaml called with language: {language}")
    # Register YAML constructors if not already done
    register_yaml_constructors()

    # Configure gettext if language is specified
    if language:
        logger.debug(f"Setting up gettext for language: {language}")
        setup_gettext_localization(language=language)
    else:
        logger.debug("No language specified, keeping current gettext config")


def get_supported_languages() -> list[str]:
    """
    Retrieve supported languages.

    Args:
        none

    Returns:
        list[str]: A list containing the available supported languages for localization.
    """

    localization_path = Path(config["locales_dir"])

    languages: list[str] = ["en"]
    logger.debug(
        f"Enumerating available languages from the localization path: {localization_path}"
    )

    if localization_path.exists():
        for item in localization_path.iterdir():
            if item.is_dir():
                logger.debug(f"Found possible supported language file: {item}")
                languages.append(item.stem)

    return languages


def get_language_data(
    language: str,
    category: str,
) -> dict[str, Any]:
    """Load a language YAML file under ``locales_dir/<language>/<category>``.

    Failures (missing file, parse error) are logged and yield an empty
    dict so callers can fall back to defaults rather than crash.

    Args:
        language (str): Language subdirectory (e.g. ``"en"``, ``"de"``).
        category (str): YAML file stem within that directory; the
            ``.yaml`` suffix is appended automatically.

    Returns:
        dict[str, Any]: Parsed YAML contents, or ``{}`` on error.
    """
    language_file = Path(
        config["locales_dir"], language, category
    ).with_suffix(".yaml")

    try:
        logger.info("Attempting to open language file: {}", language_file)
        language_data: dict[str, Any] = open_file(language_file)

        return language_data

    except FileNotFoundError:
        logger.error("language file not found: {}", language_file)
        return {}

    except Exception as e:
        logger.error("Error parsing language file: {}", e)
        return {}
