"""Django staff-session authentication for the Angular operations portal.

The browser portal authenticates Django staff accounts and relies on Django's
server-side session plus CSRF protection. Login attempts are throttled through
Django's cache to reduce password-guessing risk.

"""

import hashlib
import json

from django.conf import settings
from django.contrib.auth import authenticate, login, logout
from django.core.cache import cache
from django.http import JsonResponse
from django.middleware.csrf import get_token
from django.views.decorators.csrf import csrf_protect, ensure_csrf_cookie
from django.views.decorators.http import require_GET, require_POST


def _staff_payload(user):
    display_name = (user.get_full_name() or user.get_username()).strip()
    return {
        "id": user.pk,
        "username": user.get_username(),
        "display_name": display_name,
        "email": user.email or "",
        "is_superuser": bool(user.is_superuser),
    }


def _json_body(request):
    try:
        body = json.loads(request.body.decode("utf-8") or "{}")
    except (UnicodeDecodeError, json.JSONDecodeError):
        return None
    return body if isinstance(body, dict) else None


def _login_rate_key(request, username: str) -> str:
    remote_addr = request.META.get("REMOTE_ADDR", "unknown")
    raw = f"{remote_addr}|{username.casefold()}".encode("utf-8")
    digest = hashlib.sha256(raw).hexdigest()
    return f"admin-login-failures:{digest}"


def _is_rate_limited(rate_key: str) -> bool:
    max_attempts = int(getattr(settings, "ADMIN_LOGIN_MAX_ATTEMPTS", 5))
    return int(cache.get(rate_key, 0) or 0) >= max_attempts


def _register_failed_login(rate_key: str) -> None:
    lockout_seconds = int(getattr(settings, "ADMIN_LOGIN_LOCKOUT_SECONDS", 900))
    failures = int(cache.get(rate_key, 0) or 0) + 1
    cache.set(rate_key, failures, timeout=lockout_seconds)


@require_GET
@ensure_csrf_cookie
def admin_csrf(request):
    """Set Django's CSRF cookie before the staff login POST."""
    return JsonResponse({"csrf_token": get_token(request)})


@require_POST
@csrf_protect
def admin_login(request):
    body = _json_body(request)
    if body is None:
        return JsonResponse(
            {"detail": "The sign-in request could not be read."},
            status=400,
        )

    username = str(body.get("username") or "").strip()
    password = str(body.get("password") or "")

    if not username or not password:
        return JsonResponse(
            {"detail": "Username and password are required."},
            status=400,
        )

    rate_key = _login_rate_key(request, username)
    if _is_rate_limited(rate_key):
        return JsonResponse(
            {"detail": "Too many sign-in attempts. Please try again later."},
            status=429,
        )

    user = authenticate(request, username=username, password=password)

    # Keep the response intentionally generic so the endpoint does not reveal
    # whether a username exists or whether a known account is non-staff.
    if user is None or not user.is_active or not user.is_staff:
        _register_failed_login(rate_key)
        return JsonResponse(
            {"detail": "The supplied credentials cannot be used to sign in."},
            status=401,
        )

    cache.delete(rate_key)
    login(request, user)

    return JsonResponse(
        {
            "user": _staff_payload(user),
            "csrf_token": get_token(request),
        }
    )


@require_GET
def admin_session(request):
    user = getattr(request, "user", None)
    if not user or not user.is_authenticated:
        return JsonResponse({"detail": "Authentication required."}, status=401)

    if not user.is_active or not user.is_staff:
        return JsonResponse({"detail": "Authentication required."}, status=401)

    return JsonResponse({"user": _staff_payload(user)})


@require_POST
@csrf_protect
def admin_logout(request):
    logout(request)
    return JsonResponse({"detail": "Signed out."})
