"""
API views for error monitoring and reporting.

Provides endpoints for:
- Frontend error reporting (public, rate-limited)
- Error listing and filtering (admin only)
- Error detail view (admin only)
- Error resolution (admin only)
- Error statistics (admin only)
- Old error cleanup (superuser only)
"""

import logging

from django.db.models import Q
from rest_framework import status
from rest_framework.permissions import AllowAny, IsAdminUser
from rest_framework.response import Response
from rest_framework.throttling import AnonRateThrottle
from rest_framework.views import APIView

from apps.core.api.error_serializers import (
    ApplicationErrorListSerializer,
    ApplicationErrorSerializer,
    ErrorCleanupSerializer,
    ErrorReportSerializer,
    ErrorResolveSerializer,
    ErrorStatisticsSerializer,
)
from apps.core.models import ApplicationError
from apps.core.services import ErrorService

logger = logging.getLogger(__name__)


class ErrorReportThrottle(AnonRateThrottle):
    """Rate limit for error reporting - 10 requests per minute per IP."""

    rate = "10/min"


class ErrorReportView(APIView):
    """
    POST /api/v1/errors/report/
    
    Accept error reports from the frontend.
    Public endpoint, rate-limited to prevent abuse.
    """

    permission_classes = [AllowAny]
    throttle_classes = [ErrorReportThrottle]

    def post(self, request):
        """Record an error report from the frontend."""
        serializer = ErrorReportSerializer(data=request.data)
        serializer.validate(request.data)

        if not serializer.is_valid():
            return Response(
                {"error": "Invalid error report", "details": serializer.errors},
                status=status.HTTP_400_BAD_REQUEST,
            )

        data = serializer.validated_data

        # Capture the error
        error = ErrorService.capture_error(
            error=data["error_message"],
            source="frontend",
            request=request,
            severity=data.get("severity", "medium"),
            metadata=data.get("metadata", {}),
            environment=data.get("environment", {}),
            error_id=data.get("error_id"),
        )

        # Update error_type from the submitted data
        error.error_type = data["error_type"]
        error.error_stack = data.get("error_stack", "")
        error.error_code = data.get("error_code", "")
        error.endpoint = data.get("endpoint", "")
        error.save(update_fields=["error_type", "error_stack", "error_code", "endpoint"])

        return Response(
            {
                "status": "success",
                "error_id": str(error.error_id),
                "message": "Error report received",
            },
            status=status.HTTP_201_CREATED,
        )


class ErrorListView(APIView):
    """
    GET /api/v1/errors/
    
    List errors with filtering. Admin only.
    """

    permission_classes = [IsAdminUser]

    def get(self, request):
        """List errors with optional filters."""
        queryset = ApplicationError.objects.all()

        # Apply filters
        severity = request.query_params.get("severity")
        if severity:
            queryset = queryset.filter(severity=severity)

        source = request.query_params.get("source")
        if source:
            queryset = queryset.filter(source=source)

        error_type = request.query_params.get("error_type")
        if error_type:
            queryset = queryset.filter(error_type__icontains=error_type)

        resolved = request.query_params.get("resolved")
        if resolved is not None:
            resolved_bool = resolved.lower() in ("true", "1", "yes")
            queryset = queryset.filter(resolved=resolved_bool)

        search = request.query_params.get("search")
        if search:
            queryset = queryset.filter(
                Q(error_id__icontains=search)
                | Q(error_message__icontains=search)
                | Q(endpoint__icontains=search)
                | Q(error_type__icontains=search)
            )

        # Date range filter
        date_range = request.query_params.get("date_range", "24h")
        from datetime import timedelta

        from django.utils import timezone

        range_map = {
            "1h": timedelta(hours=1),
            "24h": timedelta(hours=24),
            "7d": timedelta(days=7),
            "30d": timedelta(days=30),
        }
        if date_range in range_map:
            cutoff = timezone.now() - range_map[date_range]
            queryset = queryset.filter(created_at__gte=cutoff)

        # Pagination
        limit = min(int(request.query_params.get("limit", 50)), 100)
        offset = int(request.query_params.get("offset", 0))

        total = queryset.count()
        errors = queryset[offset : offset + limit]

        serializer = ApplicationErrorListSerializer(errors, many=True)

        return Response(
            {
                "status": "success",
                "data": serializer.data,
                "total": total,
                "limit": limit,
                "offset": offset,
            }
        )


class ErrorDetailView(APIView):
    """
    GET /api/v1/errors/{id}/
    
    Get full error details. Admin only.
    """

    permission_classes = [IsAdminUser]

    def get(self, request, pk):
        """Get detailed error information."""
        try:
            error = ApplicationError.objects.get(pk=pk)
        except ApplicationError.DoesNotExist:
            return Response(
                {"error": "Error not found"},
                status=status.HTTP_404_NOT_FOUND,
            )

        serializer = ApplicationErrorSerializer(error)
        return Response({"status": "success", "data": serializer.data})


class ErrorResolveView(APIView):
    """
    POST /api/v1/errors/{id}/resolve/
    
    Mark an error as resolved. Admin only.
    """

    permission_classes = [IsAdminUser]

    def post(self, request, pk):
        """Mark error as resolved."""
        serializer = ErrorResolveSerializer(data=request.data)
        if not serializer.is_valid():
            return Response(
                {"error": "Invalid request", "details": serializer.errors},
                status=status.HTTP_400_BAD_REQUEST,
            )

        try:
            error = ErrorService.resolve_error(
                error_id=pk,
                user=request.user,
                notes=serializer.validated_data.get("notes", ""),
            )
        except ApplicationError.DoesNotExist:
            return Response(
                {"error": "Error not found"},
                status=status.HTTP_404_NOT_FOUND,
            )

        return Response(
            {
                "status": "success",
                "message": "Error marked as resolved",
                "error_id": str(error.error_id),
            }
        )


class ErrorStatisticsView(APIView):
    """
    GET /api/v1/errors/statistics/
    
    Get error statistics for dashboard. Admin only.
    """

    permission_classes = [IsAdminUser]

    def get(self, request):
        """Get error statistics."""
        days = int(request.query_params.get("days", 7))
        days = min(max(days, 1), 90)  # Clamp between 1 and 90

        stats = ErrorService.get_error_statistics(days=days)
        serializer = ErrorStatisticsSerializer(stats)

        return Response({"status": "success", "data": serializer.data})


class ErrorCleanupView(APIView):
    """
    POST /api/v1/errors/cleanup/
    
    Clean up old errors. Superuser only.
    """

    permission_classes = [IsAdminUser]

    def post(self, request):
        """Clean up old resolved errors."""
        # Extra check for superuser
        if not request.user.is_superuser:
            return Response(
                {"error": "Superuser access required"},
                status=status.HTTP_403_FORBIDDEN,
            )

        serializer = ErrorCleanupSerializer(data=request.data)
        if not serializer.is_valid():
            return Response(
                {"error": "Invalid request", "details": serializer.errors},
                status=status.HTTP_400_BAD_REQUEST,
            )

        days = serializer.validated_data.get("days", 30)
        deleted_count = ErrorService.cleanup_old_errors(days=days)

        return Response(
            {
                "status": "success",
                "message": f"Deleted {deleted_count} errors older than {days} days",
                "deleted_count": deleted_count,
            }
        )
