"""Runtime localization selectors — resolve locale, currency, and formatting context.

All functions accept explicit parameters so they can be used outside the
request-response cycle (Celery tasks, management commands, tests).
"""

from __future__ import annotations

from typing import Any

from simorgh.apps.localization.models import Currency, Locale


def get_locale_by_code(code: str) -> Locale | None:
    return Locale.objects.filter(code=code).select_related("language", "country").first()


def get_default_locale() -> Locale | None:
    return _default_locale()


def _default_locale() -> Locale | None:
    """Return the platform default locale, with fallback."""
    locale = (
        Locale.objects.filter(is_default=True)
        .select_related("language", "country")
        .first()
    )
    if locale is None:
        locale = (
            Locale.objects.select_related("language", "country")
            .order_by("pk")
            .first()
        )
    return locale


def get_currency_by_code(code: str) -> Currency | None:
    return Currency.objects.filter(code=code, is_enabled=True).first()


def get_effective_currency(locale: Locale) -> Currency | None:
    """Return the Currency object for a locale, falling back to USD."""
    currency = get_currency_by_code(locale.currency_code)
    if currency is None:
        currency = get_currency_by_code("USD")
    return currency


def resolve_locale(
    *,
    user: Any = None,
    tenant: Any = None,
    org_node: Any = None,
    locale_code: str | None = None,
) -> Locale:
    """Resolve the effective locale by walking the inheritance chain.

    Priority:
        1. Explicit ``locale_code`` parameter
        2. User's LocalizationProfile.locale
        3. Tenant's LocalizationProfile.locale
        4. Platform default locale (is_default=True)
        5. First available locale in DB
    """
    locale = None

    if locale_code:
        locale = get_locale_by_code(locale_code)

    if locale is None and user is not None:
        locale = _profile_locale(user)

    if locale is None and tenant is not None:
        locale = _profile_locale(tenant)

    if locale is None:
        locale = get_default_locale()

    if locale is None:
        raise RuntimeError("No locale configured in the database.")

    return locale


def _profile_locale(obj: Any) -> Locale | None:
    """Extract locale from an object that may have LocalizationProfile fields."""
    if hasattr(obj, "locale") and callable(getattr(obj, "locale", None)):
        # It's a FK descriptor — check if it has been set
        locale = getattr(obj, "locale", None)
        if locale is not None:
            return locale
    # Try the FK id attribute
    locale_id = getattr(obj, "locale_id", None)
    if locale_id is not None:
        try:
            return Locale.objects.select_related("language", "country").get(pk=locale_id)
        except Locale.DoesNotExist:
            pass
    return None
