from __future__ import annotations

from contextlib import suppress
from urllib.parse import urlparse

from django.conf import settings
from django.http import HttpRequest, HttpResponseRedirect
from django.urls import translate_url
from django.utils.http import url_has_allowed_host_and_scheme
from django.utils.translation import activate
from django.views.decorators.csrf import csrf_exempt


def _normalize_language_code(lang: str | None) -> str:
    if not lang:
        return settings.LANGUAGE_CODE

    lang = lang.replace("_", "-").lower()

    overrides = getattr(settings, "LANGUAGE_URL_OVERRIDES", {}) or {}
    if lang in overrides:
        lang = overrides[lang].lower()

    supported = {code.lower() for code, _ in getattr(settings, "LANGUAGES", [])}
    if lang not in supported:
        primary = lang.split("-")[0]
        if primary in overrides and overrides[primary].lower() in supported:
            return overrides[primary].lower()
        return settings.LANGUAGE_CODE

    return lang


def _safe_next_url(request: HttpRequest) -> str:
    next_url = (
        request.POST.get("next")
        or request.GET.get("next")
        or request.META.get("HTTP_REFERER")
        or "/"
    )
    if not url_has_allowed_host_and_scheme(
        url=next_url,
        allowed_hosts={request.get_host()},
        require_https=request.is_secure(),
    ):
        return "/"
    return next_url


LANGUAGE_SESSION_KEY = "_language"


@csrf_exempt
def set_language(request: HttpRequest):
    language = request.POST.get("language") or request.GET.get("language")
    normalized = _normalize_language_code(language)

    response = HttpResponseRedirect("/")
    if hasattr(request, "session"):
        request.session[LANGUAGE_SESSION_KEY] = normalized
    response.set_cookie(settings.LANGUAGE_COOKIE_NAME, normalized)

    activate(normalized)

    next_url = _safe_next_url(request)

    if translate_url is not None:
        with suppress(Exception):
            next_url = translate_url(next_url, normalized)
    else:
        parsed = urlparse(next_url)
        parts = [p for p in parsed.path.split("/") if p]
        supported = {code.lower() for code, _ in getattr(settings, "LANGUAGES", [])}
        if parts and parts[0].lower() in supported:
            parts[0] = normalized
            path = (
                "/" + "/".join(parts) + "/"
                if parsed.path.endswith("/")
                else "/" + "/".join(parts)
            )
            next_url = parsed._replace(path=path).geturl()

    response["Location"] = next_url
    return response
