from __future__ import annotations

from django.conf import settings
from rest_framework.exceptions import PermissionDenied, ValidationError
from rest_framework.filters import BaseFilterBackend


def _get_configured_office_header_name() -> str:
    name = getattr(settings, "OFFICE_HEADER", None)
    if name:
        return str(name)
    return "X-Office-Id"


def _get_configured_office_query_param() -> str:
    name = getattr(settings, "OFFICE_QUERY_PARAM", None)
    if name:
        return str(name)
    return "office_id"


def extract_office_id(request) -> int | None:
    if request is None:
        return None

    office_id = getattr(request, "office_id", None)
    if office_id is not None:
        try:
            office_id = int(office_id)
        except (TypeError, ValueError):
            return None

        user = getattr(request, "user", None)
        if user and getattr(user, "is_authenticated", False) and not getattr(user, "is_superuser", False):
            profile = getattr(user, "profile", None)
            if profile is None or not profile.oficinas.filter(id=office_id).exists():
                raise PermissionDenied("No tienes acceso a la oficina indicada.")

        return office_id

    header_name = _get_configured_office_header_name()
    header_value = None

    headers = getattr(request, "headers", None)
    if headers is not None:
        header_value = headers.get(header_name)

    if header_value is None:
        meta = getattr(request, "META", {}) or {}
        key = "HTTP_" + str(header_name).upper().replace("-", "_")
        header_value = meta.get(key)

    if header_value is None:
        query_params = getattr(request, "query_params", None)
        if query_params is None:
            query_params = getattr(request, "GET", None)
        if query_params is not None:
            header_value = query_params.get(_get_configured_office_query_param())

    if header_value is None:
        return None

    s = str(header_value).strip()
    if not s:
        return None
    if not s.isdigit():
        return None
    office_id = int(s)

    user = getattr(request, "user", None)
    if user and getattr(user, "is_authenticated", False) and not getattr(user, "is_superuser", False):
        profile = getattr(user, "profile", None)
        if profile is None or not profile.oficinas.filter(id=office_id).exists():
            raise PermissionDenied("No tienes acceso a la oficina indicada.")

    return office_id


def _resolve_office_filter_field(view, model) -> str | None:
    explicit = getattr(view, "office_filter_field", None)
    if explicit:
        return str(explicit)

    candidates = ["office", "oficina", "sucursal"]
    for name in candidates:
        try:
            field = model._meta.get_field(name)
        except Exception:
            continue

        if getattr(field, "is_relation", False):
            return f"{name}_id"
        return name

    return None


class OfficeFilterBackend(BaseFilterBackend):
    def filter_queryset(self, request, queryset, view):
        if request is None:
            return queryset

        if queryset is None:
            return queryset

        model = getattr(queryset, "model", None)
        if model is None:
            return queryset

        office_field = _resolve_office_filter_field(view=view, model=model)
        if not office_field:
            return queryset

        user = getattr(request, "user", None)
        office_id = extract_office_id(request)
        if office_id is None:
            if user and getattr(user, "is_authenticated", False) and getattr(user, "is_superuser", False):
                return queryset
            raise ValidationError(
                {
                    _get_configured_office_query_param(): "office_id es requerido para este recurso."
                }
            )

        return queryset.filter(**{office_field: office_id})
