"""DMS audit bounded context — query utilities.

All lookups use ``public_id`` (the UUID exposed externally) rather than the
integer database pk.
"""

from __future__ import annotations

import uuid
from typing import Optional

from django.db.models import QuerySet

from simorgh.apps.dms.audit.models import (
    AccessLog,
    DocumentAuditLog,
    SecurityEvent,
    SecurityEventSeverity,
    SecurityEventType,
)
from simorgh.apps.dms.common.exceptions import AssetNotFound


def list_document_audit_logs(
    tenant_id: int,
    document_id: int,
    action: Optional[str] = None,
) -> QuerySet:
    """Return all audit log entries for *document_id* in newest-first order."""
    qs = DocumentAuditLog.objects.filter(
        tenant_id=tenant_id,
        document_id=document_id,
    )
    if action:
        qs = qs.filter(action=action)
    return qs.order_by("-occurred_at")


def get_audit_log(tenant_id: int, log_id: str) -> DocumentAuditLog:
    """Return a single DocumentAuditLog entry by public_id, or raise AssetNotFound."""
    try:
        uid = uuid.UUID(str(log_id))
    except (ValueError, AttributeError) as exc:
        raise AssetNotFound(f"Invalid audit log id: {log_id!r}") from exc
    try:
        return DocumentAuditLog.objects.get(tenant_id=tenant_id, public_id=uid)
    except DocumentAuditLog.DoesNotExist as exc:
        raise AssetNotFound(f"AuditLog {log_id!r} not found.") from exc


def list_access_logs(
    tenant_id: int,
    document_id: int,
    access_type: Optional[str] = None,
) -> QuerySet:
    """Return all access log entries for *document_id* in newest-first order."""
    qs = AccessLog.objects.filter(
        tenant_id=tenant_id,
        document_id=document_id,
    )
    if access_type:
        qs = qs.filter(access_type=access_type)
    return qs.order_by("-occurred_at")


def list_security_events(
    tenant_id: int,
    document_id: Optional[int] = None,
    event_type: Optional[str] = None,
    severity: Optional[str] = None,
) -> QuerySet:
    """Return security events for the tenant, optionally scoped to a document."""
    qs = SecurityEvent.objects.filter(tenant_id=tenant_id)
    if document_id is not None:
        qs = qs.filter(document_id=document_id)
    if event_type:
        qs = qs.filter(event_type=event_type)
    if severity:
        qs = qs.filter(severity=severity)
    return qs.order_by("-occurred_at")


def get_security_event(tenant_id: int, event_id: str) -> SecurityEvent:
    """Return a single SecurityEvent by public_id, or raise AssetNotFound."""
    try:
        uid = uuid.UUID(str(event_id))
    except (ValueError, AttributeError) as exc:
        raise AssetNotFound(f"Invalid security event id: {event_id!r}") from exc
    try:
        return SecurityEvent.objects.get(tenant_id=tenant_id, public_id=uid)
    except SecurityEvent.DoesNotExist as exc:
        raise AssetNotFound(f"SecurityEvent {event_id!r} not found.") from exc
