#!/usr/bin/env python
# -*- coding: UTF-8 -*-

import logging
import traceback

from django.db.models import ProtectedError, RestrictedError
from django.http import Http404
from rest_framework.exceptions import APIException as DRFAPIException
from rest_framework.exceptions import AuthenticationFailed, PermissionDenied
from rest_framework.status import HTTP_401_UNAUTHORIZED
from rest_framework.views import exception_handler, set_rollback

from django_base_ai.utils.json_response import ErrorResponse

logger = logging.getLogger(__name__)


def custom_exception_handler(ex, context):
    """
    统一异常拦截处理
    目的:(1)取消所有的500异常响应,统一响应为标准错误返回
        (2)准确显示错误信息
    :param ex:
    :param context:
    :return:
    """
    msg = ""
    code = 4000
    # 调用默认的异常处理函数
    response = exception_handler(ex, context)
    if isinstance(ex, AuthenticationFailed):
        # 如果是身份验证错误
        detail = response.data.get("detail") if response else None
        if response and detail == "Given token not valid for any token type":
            code = 402
            msg = "身份认证已过期,请重新登录"
        elif response and detail == "Token is blacklisted":
            # token在黑名单
            return ErrorResponse(status=HTTP_401_UNAUTHORIZED)
        elif isinstance(detail, dict):
            # authentication.py 抛出的 detail={"code": 402, "msg": "..."}
            code = int(detail.get("code", 402))
            msg = detail.get("msg", "用户名或密码输入错误,请重新登录")
        else:
            code = 402
            msg = "用户名或密码输入错误,请重新登录"
    elif isinstance(ex, Http404):
        code = 400
        msg = "接口地址不正确"
    elif isinstance(ex, DRFAPIException):
        set_rollback()
        msg = ex.detail
        if isinstance(ex, PermissionDenied):
            msg = f"{msg} ({context['request'].method}: {context['request'].path})"
        if isinstance(msg, dict):
            for k, v in msg.items():
                for i in v:
                    msg = f"{k}:{i}"
    elif isinstance(ex, (ProtectedError, RestrictedError)):
        set_rollback()
        msg = "无法删除:该条数据与其他数据有相关绑定"
    # elif isinstance(ex, DatabaseError):
    #     set_rollback()
    #     msg = "接口服务器异常,请联系管理员"
    elif isinstance(ex, Exception):
        logger.exception(traceback.format_exc())
        msg = str(ex)
    return ErrorResponse(msg=msg, code=code)
