"""
Custom exception handling for ThrillWiki API.
Provides standardized error responses following Django styleguide patterns.
"""

from typing import Any

from django.core.exceptions import (
    PermissionDenied,
)
from django.core.exceptions import (
    ValidationError as DjangoValidationError,
)
from django.http import Http404
from rest_framework import status
from rest_framework.exceptions import (
    NotFound,
)
from rest_framework.exceptions import (
    PermissionDenied as DRFPermissionDenied,
)
from rest_framework.exceptions import (
    ValidationError as DRFValidationError,
)
from rest_framework.response import Response
from rest_framework.views import exception_handler

from ..exceptions import ThrillWikiException
from ..logging import get_logger, log_exception

logger = get_logger(__name__)


def custom_exception_handler(exc: Exception, context: dict[str, Any]) -> Response | None:
    """
    Custom exception handler for DRF that provides standardized error responses.

    Returns:
        Response with standardized error format or None to fallback to default handler
    """
    # Call REST framework's default exception handler first
    response = exception_handler(exc, context)

    if response is not None:
        # Standardize the error response format
        custom_response_data = {
            "status": "error",
            "error": {
                "code": _get_error_code(exc),
                "message": _get_error_message(exc, response.data),
                "details": _get_error_details(exc, response.data),
            },
            "data": None,
        }

        # Add request context for debugging
        if hasattr(context.get("request"), "user"):
            custom_response_data["error"]["request_user"] = str(context["request"].user)

        # Log the error for monitoring
        log_exception(
            logger,
            exc,
            context={"response_status": response.status_code},
            request=context.get("request"),
        )

        response.data = custom_response_data

    # Handle ThrillWiki custom exceptions
    elif isinstance(exc, ThrillWikiException):
        custom_response_data = {
            "status": "error",
            "error": exc.to_dict(),
            "data": None,
        }

        log_exception(
            logger,
            exc,
            context={"response_status": exc.status_code},
            request=context.get("request"),
        )
        response = Response(custom_response_data, status=exc.status_code)

    # Handle specific Django exceptions that DRF doesn't catch
    elif isinstance(exc, DjangoValidationError):
        custom_response_data = {
            "status": "error",
            "error": {
                "code": "VALIDATION_ERROR",
                "message": "Validation failed",
                "details": _format_django_validation_errors(exc),
            },
            "data": None,
        }

        log_exception(
            logger,
            exc,
            context={"response_status": status.HTTP_400_BAD_REQUEST},
            request=context.get("request"),
        )
        response = Response(custom_response_data, status=status.HTTP_400_BAD_REQUEST)

    elif isinstance(exc, Http404):
        custom_response_data = {
            "status": "error",
            "error": {
                "code": "NOT_FOUND",
                "message": "Resource not found",
                "details": str(exc) if str(exc) else None,
            },
            "data": None,
        }

        log_exception(
            logger,
            exc,
            context={"response_status": status.HTTP_404_NOT_FOUND},
            request=context.get("request"),
        )
        response = Response(custom_response_data, status=status.HTTP_404_NOT_FOUND)

    elif isinstance(exc, PermissionDenied):
        custom_response_data = {
            "status": "error",
            "error": {
                "code": "PERMISSION_DENIED",
                "message": "Permission denied",
                "details": str(exc) if str(exc) else None,
            },
            "data": None,
        }

        log_exception(
            logger,
            exc,
            context={"response_status": status.HTTP_403_FORBIDDEN},
            request=context.get("request"),
        )
        response = Response(custom_response_data, status=status.HTTP_403_FORBIDDEN)

    # Catch-all for any other exceptions that might slip through
    # This ensures we ALWAYS return JSON for API endpoints
    else:
        # Check if this is an API request by looking at the URL path
        request = context.get("request")
        if request and hasattr(request, "path") and "/api/" in request.path:
            # This is an API request, so we must return JSON
            custom_response_data = {
                "status": "error",
                "error": {
                    "code": exc.__class__.__name__.upper(),
                    "message": str(exc) if str(exc) else "An unexpected error occurred",
                    "details": None,
                },
                "data": None,
            }

            # Add request context for debugging
            if hasattr(request, "user"):
                custom_response_data["error"]["request_user"] = str(request.user)

            # Log the error for monitoring
            log_exception(
                logger,
                exc,
                context={"response_status": status.HTTP_500_INTERNAL_SERVER_ERROR},
                request=request,
            )

            response = Response(custom_response_data, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

    return response


def _get_error_code(exc: Exception) -> str:
    """Extract or determine error code from exception."""
    # Use getattr + isinstance to avoid static type checker errors
    default_code = getattr(exc, "default_code", None)
    if isinstance(default_code, str):
        return default_code.upper()

    if isinstance(exc, DRFValidationError):
        return "VALIDATION_ERROR"
    elif isinstance(exc, NotFound):
        return "NOT_FOUND"
    elif isinstance(exc, DRFPermissionDenied):
        return "PERMISSION_DENIED"

    return exc.__class__.__name__.upper()


def _get_error_message(exc: Exception, response_data: Any) -> str:
    """Extract user-friendly error message."""
    if isinstance(response_data, dict):
        # Handle DRF validation errors
        if "detail" in response_data:
            return str(response_data["detail"])
        elif "non_field_errors" in response_data:
            errors = response_data["non_field_errors"]
            return errors[0] if isinstance(errors, list) and errors else str(errors)
        elif isinstance(response_data, dict) and len(response_data) == 1:
            key, value = next(iter(response_data.items()))
            if isinstance(value, list) and value:
                return f"{key}: {value[0]}"
            return f"{key}: {value}"

    # Fallback to exception message
    return str(exc) if str(exc) else "An error occurred"


def _get_error_details(exc: Exception, response_data: Any) -> dict[str, Any] | None:
    """Extract detailed error information for debugging."""
    if isinstance(response_data, dict) and len(response_data) > 1:
        return response_data

    # Use getattr to avoid static type-checker errors when Exception doesn't define `detail`
    detail = getattr(exc, "detail", None)
    if isinstance(detail, dict):
        return detail

    return None


def _format_django_validation_errors(
    exc: DjangoValidationError,
) -> dict[str, Any]:
    """Format Django ValidationError for API response."""
    if hasattr(exc, "error_dict"):
        # Field-specific errors
        return {field: [str(error) for error in errors] for field, errors in exc.error_dict.items()}
    elif hasattr(exc, "error_list"):
        # Non-field errors
        return {"non_field_errors": [str(error) for error in exc.error_list]}

    return {"non_field_errors": [str(exc)]}


# Removed _log_api_error - using centralized logging instead
