from __future__ import annotations

from functools import lru_cache
from urllib.parse import urlsplit, urlunsplit

from django.conf import settings

from wagtail.models import Locale, Page

from .middleware import get_current_request


@lru_cache(maxsize=1)
def get_known_locale_codes() -> set[str]:
    locale_codes = {
        normalize_language_code(locale.language_code)
        for locale in Locale.objects.all().only("language_code")
    }
    locale_codes.discard(None)
    return locale_codes


def normalize_language_code(language_code: str | None) -> str | None:
    if not language_code:
        return None
    return str(language_code).strip().lower().replace("_", "-")


def get_default_language_code(default: str = "nl") -> str:
    code = normalize_language_code(getattr(settings, "LANGUAGE_CODE", None))
    return code or default


def get_active_language_code(
    request=None,
    language_code: str | None = None,
    default: str = "nl",
) -> str:
    code = normalize_language_code(language_code)
    if code:
        return code

    request = request or get_current_request()
    if request is not None:
        code = normalize_language_code(getattr(request, "LANGUAGE_CODE", None))
        if code:
            return code

    return get_default_language_code(default=default)


def is_internal_path(value: str | None) -> bool:
    if not value:
        return False
    if value.startswith(("http://", "https://", "//", "mailto:", "tel:", "#")):
        return False
    return value.startswith("/")


def localize_internal_path(
    value: str | None,
    request=None,
    language_code: str | None = None,
    default_language: str = "nl",
) -> str | None:
    if not value:
        return value
    if not is_internal_path(value):
        return value

    code = get_active_language_code(
        request=request,
        language_code=language_code,
        default=default_language,
    )
    default_code = normalize_language_code(default_language) or "nl"

    parts = urlsplit(value)
    path = parts.path or "/"
    locale_codes = get_known_locale_codes()

    stripped = path.lstrip("/")
    first_segment = stripped.split("/", 1)[0] if stripped else ""

    if code == default_code:
        if first_segment in locale_codes and first_segment != default_code:
            remainder = stripped[len(first_segment) :].lstrip("/")
            path = f"/{remainder}" if remainder else "/"
    else:
        if first_segment in locale_codes:
            if first_segment != code:
                remainder = stripped[len(first_segment) :].lstrip("/")
                path = f"/{code}/{remainder}" if remainder else f"/{code}/"
        else:
            if path == "/":
                path = f"/{code}/"
            else:
                path = f"/{code}{path}"

    return urlunsplit((parts.scheme, parts.netloc, path, parts.query, parts.fragment))


def resolve_page_for_language(page, request=None, language_code: str | None = None):
    if not isinstance(page, Page):
        return page

    code = get_active_language_code(request=request, language_code=language_code)
    page_code = normalize_language_code(getattr(page.locale, "language_code", None))
    if page_code == code:
        return page

    translation_key = getattr(page, "translation_key", None)
    if not translation_key:
        return page

    translated = (
        Page.objects.filter(
            translation_key=translation_key,
            locale__language_code=code,
        )
        .specific()
        .first()
    )
    return translated or page
