"""
ViewSets for admin analytics endpoints.

Provides read/write access to RequestMetadata, ApprovalTransactionMetric,
and a read-only aggregation endpoint for ErrorSummary.
"""

from datetime import timedelta

from django.db.models import Avg, Count, F, Q
from django.db.models.functions import TruncDate
from django.utils import timezone
from django_filters import rest_framework as filters
from rest_framework import status, viewsets
from rest_framework.decorators import action
from rest_framework.permissions import IsAdminUser, IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView

from apps.core.models import ApprovalTransactionMetric, RequestMetadata

from .analytics_serializers import (
    ApprovalTransactionMetricSerializer,
    ErrorSummarySerializer,
    RequestMetadataCreateSerializer,
    RequestMetadataResolveSerializer,
    RequestMetadataSerializer,
)


class RequestMetadataFilter(filters.FilterSet):
    """Filter for RequestMetadata queries."""

    error_type__ne = filters.CharFilter(field_name="error_type", method="filter_not_equal")
    created_at__gte = filters.IsoDateTimeFilter(field_name="created_at", lookup_expr="gte")
    created_at__lte = filters.IsoDateTimeFilter(field_name="created_at", lookup_expr="lte")

    class Meta:
        model = RequestMetadata
        fields = {
            "error_type": ["exact", "isnull"],
            "severity": ["exact"],
            "is_resolved": ["exact"],
            "success": ["exact"],
            "http_status": ["exact", "gte", "lte"],
            "user": ["exact"],
            "endpoint": ["exact", "icontains"],
        }

    def filter_not_equal(self, queryset, name, value):
        """Handle the error_type__ne filter for non-null error types."""
        # The frontend sends a JSON object for 'not null' filter
        # We interpret this as 'error_type is not null'
        if value:
            return queryset.exclude(error_type__isnull=True)
        return queryset


class RequestMetadataViewSet(viewsets.ModelViewSet):
    """
    ViewSet for request metadata CRUD operations.
    
    Supports filtering by error_type, severity, date range, etc.
    Use the expand=request_breadcrumbs query parameter to include breadcrumbs.
    """

    queryset = RequestMetadata.objects.all()
    permission_classes = [IsAuthenticated]
    filterset_class = RequestMetadataFilter
    ordering_fields = ["created_at", "severity", "error_type"]
    ordering = ["-created_at"]

    def get_serializer_class(self):
        if self.action == "create":
            return RequestMetadataCreateSerializer
        return RequestMetadataSerializer

    def get_queryset(self):
        """Optimize queryset with prefetch for breadcrumbs if expanded."""
        queryset = super().get_queryset()
        expand = self.request.query_params.get("expand", "")
        
        if "request_breadcrumbs" in expand:
            queryset = queryset.prefetch_related("request_breadcrumbs")
        
        return queryset

    def perform_create(self, serializer):
        """Associate request metadata with current user if authenticated."""
        user = self.request.user if self.request.user.is_authenticated else None
        serializer.save(user=user)

    @action(detail=True, methods=["post"], permission_classes=[IsAdminUser])
    def resolve(self, request, pk=None):
        """Mark a request metadata entry as resolved."""
        instance = self.get_object()
        serializer = RequestMetadataResolveSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)

        instance.is_resolved = True
        instance.resolved_at = timezone.now()
        instance.resolved_by = request.user
        instance.resolution_notes = serializer.validated_data.get("resolution_notes", "")
        instance.save(update_fields=["is_resolved", "resolved_at", "resolved_by", "resolution_notes"])

        return Response(RequestMetadataSerializer(instance).data)


class ApprovalTransactionMetricFilter(filters.FilterSet):
    """Filter for ApprovalTransactionMetric queries."""

    created_at__gte = filters.IsoDateTimeFilter(field_name="created_at", lookup_expr="gte")
    created_at__lte = filters.IsoDateTimeFilter(field_name="created_at", lookup_expr="lte")

    class Meta:
        model = ApprovalTransactionMetric
        fields = {
            "success": ["exact"],
            "moderator_id": ["exact"],
            "submitter_id": ["exact"],
            "submission_id": ["exact"],
        }


class ApprovalTransactionMetricViewSet(viewsets.ReadOnlyModelViewSet):
    """
    Read-only ViewSet for approval transaction metrics.
    
    Provides analytics data about moderation approval operations.
    """

    queryset = ApprovalTransactionMetric.objects.all()
    serializer_class = ApprovalTransactionMetricSerializer
    permission_classes = [IsAuthenticated]
    filterset_class = ApprovalTransactionMetricFilter
    ordering_fields = ["created_at", "duration_ms", "success"]
    ordering = ["-created_at"]


class ErrorSummaryView(APIView):
    """
    Aggregation endpoint for error summary statistics.
    
    Returns daily error counts grouped by error_type and severity,
    similar to the Supabase error_summary view.
    """

    permission_classes = [IsAuthenticated]

    def get(self, request):
        """Get aggregated error summary data."""
        # Default to last 30 days
        days = int(request.query_params.get("days", 30))
        since = timezone.now() - timedelta(days=days)

        # Aggregate error data by date, error_type, and severity
        summary = (
            RequestMetadata.objects.filter(
                created_at__gte=since,
                error_type__isnull=False,
            )
            .annotate(date=TruncDate("created_at"))
            .values("date", "error_type", "severity")
            .annotate(
                error_count=Count("id"),
                resolved_count=Count("id", filter=Q(is_resolved=True)),
                affected_users=Count("user", distinct=True),
                avg_resolution_minutes=Avg(
                    (F("resolved_at") - F("created_at")),
                    filter=Q(is_resolved=True, resolved_at__isnull=False),
                ),
            )
            .order_by("-date", "-error_count")
        )

        # Convert timedelta to minutes for avg_resolution_minutes
        results = []
        for item in summary:
            if item["avg_resolution_minutes"]:
                item["avg_resolution_minutes"] = item["avg_resolution_minutes"].total_seconds() / 60
            results.append(item)

        serializer = ErrorSummarySerializer(results, many=True)
        return Response(serializer.data)
