"""Audit log API views."""
from __future__ import annotations

from datetime import datetime

from rest_framework import status
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import IsAuthenticated
from rest_framework.request import Request
from rest_framework.response import Response

from simorgh.apps.audit import selectors as sel
from simorgh.apps.audit.models import AuditLog


def _serialize_entry(entry: AuditLog) -> dict:
    return {
        "id": entry.pk,
        "public_id": str(entry.public_id),
        "action": entry.action,
        "resource_type": entry.resource_type,
        "resource_id": entry.resource_id,
        "actor_id": entry.actor_id,
        "organization_node_id": entry.organization_node_id,
        "before": entry.before,
        "after": entry.after,
        "ip_address": entry.ip_address,
        "user_agent": entry.user_agent,
        "extra": entry.extra,
        "created_at": entry.created_at.isoformat(),
    }


@api_view(["GET"])
@permission_classes([IsAuthenticated])
def audit_log_list(request: Request) -> Response:
    """GET /api/v1/audit/log/

    Returns audit log entries for the current tenant.
    Staff only.

    Query params:
      resource_type — filter by resource type string
      resource_id   — filter by resource id
      actor_id      — filter by actor user PK
      action        — filter by action string
      from          — ISO 8601 datetime (inclusive)
      to            — ISO 8601 datetime (inclusive)
      limit         — max rows (default 100, max 500)
    """
    if not request.user.is_staff:
        return Response({"detail": "Forbidden."}, status=status.HTTP_403_FORBIDDEN)

    tenant = getattr(request, "tenant", None)
    if tenant is None:
        return Response({"detail": "Tenant not found."}, status=status.HTTP_404_NOT_FOUND)

    params = request.query_params
    resource_type = params.get("resource_type") or None
    resource_id = params.get("resource_id") or None
    actor_id_raw = params.get("actor_id")
    actor_id = int(actor_id_raw) if actor_id_raw and actor_id_raw.isdigit() else None
    action = params.get("action") or None

    from_dt: datetime | None = None
    to_dt: datetime | None = None
    try:
        if params.get("from"):
            from_dt = datetime.fromisoformat(params["from"])
        if params.get("to"):
            to_dt = datetime.fromisoformat(params["to"])
    except ValueError:
        return Response({"error": {"code": "invalid_datetime", "message": "Use ISO 8601 format."}},
                        status=status.HTTP_400_BAD_REQUEST)

    limit_raw = params.get("limit", "100")
    try:
        limit = min(int(limit_raw), 500)
    except (ValueError, TypeError):
        limit = 100

    qs = sel.list_audit_log(
        tenant.pk,
        resource_type=resource_type,
        resource_id=resource_id,
        actor_id=actor_id,
        action=action,
        from_dt=from_dt,
        to_dt=to_dt,
        limit=limit,
    )

    return Response({"count": qs.count() if hasattr(qs, "count") else len(qs),
                     "results": [_serialize_entry(e) for e in qs]})


@api_view(["GET"])
@permission_classes([IsAuthenticated])
def audit_log_detail(request: Request, pk: int) -> Response:
    """GET /api/v1/audit/log/<pk>/"""
    if not request.user.is_staff:
        return Response({"detail": "Forbidden."}, status=status.HTTP_403_FORBIDDEN)

    tenant = getattr(request, "tenant", None)
    if tenant is None:
        return Response({"detail": "Tenant not found."}, status=status.HTTP_404_NOT_FOUND)

    try:
        entry = sel.get_audit_entry(pk, tenant.pk)
    except AuditLog.DoesNotExist:
        return Response({"detail": "Not found."}, status=status.HTTP_404_NOT_FOUND)

    return Response(_serialize_entry(entry))
