from __future__ import annotations

import re
from typing import Any, Iterable

I18N_SETTINGS_KEY = "i18n"

DEFAULT_LANGUAGE_PACKAGES: tuple[dict[str, str], ...] = (
    {"code": "en", "label": "English", "native_label": "English"},
    {"code": "de", "label": "German", "native_label": "Deutsch"},
)


def normalize_language_code(value: object) -> str:
    raw = str(value or "").strip().lower().replace("_", "-")
    parts = [part for part in re.split(r"[^a-z0-9]+", raw) if part]
    return "-".join(parts)


def language_code_candidates(value: object) -> tuple[str, ...]:
    code = normalize_language_code(value)
    if not code:
        return ()
    primary = code.split("-", 1)[0]
    return tuple(dict.fromkeys((code, primary)))


def resolve_language_code(value: object, allowed_codes: Iterable[str]) -> str:
    allowed = {normalize_language_code(code) for code in allowed_codes if normalize_language_code(code)}
    for candidate in language_code_candidates(value):
        if candidate in allowed:
            return candidate
    return ""


def i18n_settings(settings: dict[str, Any] | None) -> dict[str, Any]:
    raw = (settings or {}).get(I18N_SETTINGS_KEY)
    return dict(raw) if isinstance(raw, dict) else {}


def normalize_language_packages(raw_packages: object = None) -> list[dict[str, str]]:
    packages: dict[str, dict[str, str]] = {}
    for item in DEFAULT_LANGUAGE_PACKAGES:
        packages[item["code"]] = dict(item)

    if isinstance(raw_packages, (list, tuple)):
        for raw in raw_packages:
            if not isinstance(raw, dict):
                continue
            code = normalize_language_code(raw.get("code"))
            if not code:
                continue
            label = str(raw.get("label") or code.upper()).strip()
            native_label = str(raw.get("native_label") or raw.get("nativeLabel") or label).strip()
            packages[code] = {"code": code, "label": label, "native_label": native_label}

    return list(packages.values())


def system_language_packages(settings: dict[str, Any] | None) -> list[dict[str, str]]:
    return normalize_language_packages(i18n_settings(settings).get("available_languages"))


def normalize_enabled_language_codes(
    codes: object,
    available_languages: Iterable[dict[str, Any]],
    *,
    default_locale: object = None,
    fallback_codes: Iterable[str] = ("en", "de"),
) -> list[str]:
    available_codes = [normalize_language_code(item.get("code")) for item in available_languages if isinstance(item, dict)]
    available = {code for code in available_codes if code}
    requested: list[str] = []
    if isinstance(codes, (list, tuple, set)):
        requested = [normalize_language_code(item) for item in codes]
    if not requested:
        requested = [normalize_language_code(item) for item in fallback_codes]

    enabled: list[str] = []
    for item in requested:
        code = resolve_language_code(item, available)
        if code and code not in enabled:
            enabled.append(code)

    default_code = resolve_language_code(default_locale, available)
    if default_code and default_code not in enabled:
        enabled.insert(0, default_code)

    if enabled:
        return enabled
    if "en" in available:
        return ["en"]
    return available_codes[:1]


def system_enabled_language_codes(settings: dict[str, Any] | None, *, default_locale: object = None) -> list[str]:
    i18n = i18n_settings(settings)
    raw_enabled = i18n.get("enabled_language_codes", i18n.get("enabled_languages"))
    return normalize_enabled_language_codes(raw_enabled, system_language_packages(settings), default_locale=default_locale)


def tenant_enabled_language_codes(
    tenant_settings: dict[str, Any] | None,
    system_enabled_codes: Iterable[str],
    *,
    default_locale: object = None,
) -> list[str]:
    enabled = [normalize_language_code(code) for code in system_enabled_codes if normalize_language_code(code)]
    available = [{"code": code} for code in enabled]
    raw_enabled = i18n_settings(tenant_settings).get("enabled_language_codes")
    return normalize_enabled_language_codes(raw_enabled, available, default_locale=default_locale, fallback_codes=enabled)


def user_enabled_language_codes(user_settings: dict[str, Any] | None, tenant_enabled_codes: Iterable[str]) -> list[str]:
    enabled = [normalize_language_code(code) for code in tenant_enabled_codes if normalize_language_code(code)]
    available = [{"code": code} for code in enabled]
    raw_enabled = i18n_settings(user_settings).get("enabled_language_codes")
    return normalize_enabled_language_codes(raw_enabled, available, fallback_codes=enabled)


def preferred_language_code(user_settings: dict[str, Any] | None, allowed_codes: Iterable[str], *, default_locale: object = None) -> str:
    enabled = [normalize_language_code(code) for code in allowed_codes if normalize_language_code(code)]
    preferred = resolve_language_code(i18n_settings(user_settings).get("preferred_language"), enabled)
    if preferred:
        return preferred
    default = resolve_language_code(default_locale, enabled)
    if default:
        return default
    return enabled[0] if enabled else "en"


def update_i18n_settings(settings: dict[str, Any] | None, **values: Any) -> dict[str, Any]:
    updated = dict(settings or {})
    current = i18n_settings(updated)
    current.update(values)
    updated[I18N_SETTINGS_KEY] = current
    return updated


def system_i18n_payload(settings_item: Any | None) -> dict[str, object]:
    settings = getattr(settings_item, "settings", None)
    packages = system_language_packages(settings)
    available_codes = [item["code"] for item in packages]
    default_language = resolve_language_code(getattr(settings_item, "default_locale", None), available_codes) or "en"
    enabled = system_enabled_language_codes(settings, default_locale=default_language)
    if default_language not in enabled:
        default_language = enabled[0] if enabled else "en"
    return {
        "available_languages": packages,
        "enabled_languages": enabled,
        "default_language": default_language,
    }
