import traceback
from core.logger import logger
from rest_framework.exceptions import APIException
from core.response import fail_response
from rest_framework.views import exception_handler as drf_exception_handler
from rest_framework import status
from rest_framework.response import Response


class CustomAPIException(APIException):
    status_code = 400
    default_detail = "Bad request"
    default_code = "bad_request"

    def __init__(self, detail=None, status_code=None):
        if status_code is not None:
            self.status_code = status_code
        print(status_code, '>>>>>>>>>>>>>>>>>>>>>')
        super().__init__(detail or self.default_detail)


DEFAULT_MESSAGES = {
    status.HTTP_400_BAD_REQUEST: "Bad request.",
    status.HTTP_401_UNAUTHORIZED: "Authentication required.",
    status.HTTP_403_FORBIDDEN: "Permission denied.",
    status.HTTP_404_NOT_FOUND: "Resource not found.",
    status.HTTP_405_METHOD_NOT_ALLOWED: "Method not allowed.",
    status.HTTP_406_NOT_ACCEPTABLE: "Not acceptable.",
    status.HTTP_415_UNSUPPORTED_MEDIA_TYPE: "Unsupported media type.",
    status.HTTP_429_TOO_MANY_REQUESTS: "Too many requests.",
    status.HTTP_500_INTERNAL_SERVER_ERROR: "Internal server error.",
}


def combine_error_messages(errors) -> str:
    if isinstance(errors, dict):
        parts = []
        for field, msgs in errors.items():
            if isinstance(msgs, (list, tuple)):
                for msg in msgs:
                    parts.append(f"{msg}")
                    # parts.append(f"{field}: {msg}")
            else:
                parts.append(f"{msgs}")
                # parts.append(f"{field}: {msgs}")
        return " | ".join(parts)
    if isinstance(errors, (list, tuple)):
        return " | ".join(str(m) for m in errors)
    return str(errors)


def custom_exception_handler(exc, context):
    # Let DRF build the base Response (status + data)
    response = drf_exception_handler(exc, context)

    view = context.get("view", None)
    request = context.get("request", None)

    if response is not None:
        code = response.status_code
        data = response.data

        # ---------------------- 🔥 LOG HERE ------------------------
        logger.error(
            f"Handled Exception [{code}] in {view.__class__.__name__ if view else 'UnknownView'}: "
            f"{exc} | Path: {request.path if request else 'UnknownPath'} | Data: {data}"
        )
        # -----------------------------------------------------------

        # Heuristic:
        # - If body is a dict/list *and* not a simple {"detail": "..."} → treat as validation-ish
        is_detail_str = (
                isinstance(data, dict) and "detail" in data and isinstance(data["detail"], str)
        )
        is_structured_errors = isinstance(data, (dict, list)) and not is_detail_str

        if is_structured_errors:
            # e.g., serializer field errors dict/list
            message = combine_error_messages(data) or DEFAULT_MESSAGES.get(code, "Request failed.")
            errors = data
            extra = None
        else:
            # Most DRF exceptions give {"detail": "..."} (auth, perms, 404, 405, etc.)
            detail = data.get("detail") if isinstance(data, dict) else data
            message = str(detail) if detail else DEFAULT_MESSAGES.get(code, "Request failed.")
            errors = None

            # If this is a throttling response, DRF puts a wait on the exception; include it if present
            wait = getattr(exc, "wait", None)
            extra = {"retryAfter": wait} if wait is not None else None

        response.data = fail_response(code, message, errors)
        return response

    # ---------------------- 🔥 LOG HERE ------------------------
    logger.critical(
        f"Unhandled Exception in {context.get('view', 'UnknownView')}: {exc}\n"
        f"Path: {request.path if request else 'UnknownPath'}\n"
        f"Traceback: {traceback.format_exc()}"
    )
    # -----------------------------------------------------------

    # Unhandled → 500 envelope
    return Response(
        fail_response(status.HTTP_500_INTERNAL_SERVER_ERROR, DEFAULT_MESSAGES[500]),
        status=status.HTTP_500_INTERNAL_SERVER_ERROR,
    )
