import logging
import traceback

from rest_framework.response import Response
from rest_framework.views import exception_handler as drf_exception_handler

logger = logging.getLogger('api')


def api_response(code, message, data=None, error=None):
    """
    Standard API response wrapper.

    {
        "status_code": 200,
        "message": "...",
        "error": null,
        "data": {...}
    }
    """
    return Response(
        {
            "status_code": code,
            "message": message,
            "error": error,
            "data": data,
        },
        status=code,
    )


def _format_exception(exc):
    """Return exact error string for API response (safe for clients)."""
    exc_type = type(exc).__name__
    exc_msg = str(exc) if exc else ''
    return f"{exc_type}: {exc_msg}" if exc_msg else exc_type


def custom_exception_handler(exc, context):
    """
    Wrap ALL exceptions in the standard api_response envelope.
    DRF-handled exceptions get formatted; unhandled (e.g. DB errors) get caught
    and returned with exact error message in our format.
    """
    response = drf_exception_handler(exc, context)

    if response is not None:
        code = response.status_code
        data = response.data
        _messages = {
            400: 'Bad request.',
            401: 'Authentication credentials were not provided or are invalid.',
            403: 'You do not have permission to perform this action.',
            404: 'The requested resource was not found.',
            405: 'Method not allowed.',
            429: 'Too many requests.',
        }
        message = _messages.get(code, 'An error occurred.')
        if isinstance(data, dict) and 'detail' in data and len(data) == 1:
            message = str(data['detail'])
            error = None
        else:
            error = data
        response.data = {
            "status_code": code,
            "message": message,
            "error": error,
            "data": None,
        }
        return response

    # Unhandled exception (DB errors, etc.): return exact error in our format
    error_str = _format_exception(exc)
    logger.error(
        'Unhandled API exception: %s\n%s',
        error_str,
        traceback.format_exc(),
    )
    return Response(
        {
            "status_code": 500,
            "message": "An error occurred.",
            "error": error_str,
            "data": None,
        },
        status=500,
    )
