from rest_framework import exceptions, status
from rest_framework.response import Response
from rest_framework.views import exception_handler
from rest_framework_simplejwt.exceptions import InvalidToken

from flower.error_code import AuthErrorCode


def auth_error_response(*, error_code: AuthErrorCode, code: str, message: str, http_status: int, extra=None):
    data = {
        'error_code': int(error_code),
        'code': code,
        'message': message,
        'detail': message,
    }
    if extra:
        data.update(extra)
    return Response(data, status=http_status)


def _stringify_detail(detail):
    if hasattr(detail, 'code'):
        return str(detail), str(detail.code)
    return str(detail), None


def _extract_exception_detail(exc):
    detail = getattr(exc, 'detail', None)
    if isinstance(detail, dict):
        raw_detail = detail.get('detail')
        raw_code = detail.get('code')
        messages = detail.get('messages')
        message = str(raw_detail) if raw_detail is not None else ''
        code = str(raw_code) if raw_code is not None else None
        extra = {'messages': messages} if messages is not None else None
        return message, code, extra

    message, code = _stringify_detail(detail)
    return message, code, None


def custom_exception_handler(exc, context):
    if isinstance(exc, InvalidToken):
        _, _, extra = _extract_exception_detail(exc)
        return auth_error_response(
            error_code=AuthErrorCode.TOKEN_NOT_VALID,
            code='token_not_valid',
            message='Token 无效或已过期',
            http_status=status.HTTP_401_UNAUTHORIZED,
            extra=extra,
        )

    if isinstance(exc, exceptions.NotAuthenticated):
        return auth_error_response(
            error_code=AuthErrorCode.NOT_AUTHENTICATED,
            code='not_authenticated',
            message='未提供认证凭据',
            http_status=status.HTTP_401_UNAUTHORIZED,
        )

    if isinstance(exc, exceptions.AuthenticationFailed):
        message, code, extra = _extract_exception_detail(exc)
        if code == 'bad_authorization_header':
            return auth_error_response(
                error_code=AuthErrorCode.BAD_AUTHORIZATION_HEADER,
                code='bad_authorization_header',
                message='Authorization 请求头格式错误',
                http_status=status.HTTP_401_UNAUTHORIZED,
            )
        if code == 'user_not_found':
            return auth_error_response(
                error_code=AuthErrorCode.TOKEN_USER_NOT_FOUND,
                code='token_user_not_found',
                message='Token 对应用户不存在',
                http_status=status.HTTP_401_UNAUTHORIZED,
            )
        if code == 'user_inactive':
            return auth_error_response(
                error_code=AuthErrorCode.TOKEN_USER_INACTIVE,
                code='token_user_inactive',
                message='Token 对应用户已被禁用',
                http_status=status.HTTP_401_UNAUTHORIZED,
            )

        return auth_error_response(
            error_code=AuthErrorCode.TOKEN_NOT_VALID,
            code=code or 'authentication_failed',
            message=message or '认证失败',
            http_status=status.HTTP_401_UNAUTHORIZED,
            extra=extra,
        )

    if isinstance(exc, exceptions.PermissionDenied):
        return auth_error_response(
            error_code=AuthErrorCode.PERMISSION_DENIED,
            code='permission_denied',
            message='无权限访问该资源',
            http_status=status.HTTP_403_FORBIDDEN,
        )

    return exception_handler(exc, context)
