package com.kym.common.handler;

import cn.dev33.satoken.exception.NotLoginException;
import cn.dev33.satoken.exception.NotPermissionException;
import cn.dev33.satoken.exception.NotRoleException;
import com.kym.common.R;
import com.kym.common.exception.BaseException;
import com.kym.common.exception.BusinessException;
import com.kym.common.exception.ChargeException;
import com.kym.common.exception.PlatformCommunicationException;
import com.kym.common.exception.PlatformPushException;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.ConstraintViolationException;
import jakarta.validation.ValidationException;
import org.apache.ibatis.jdbc.Null;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.util.stream.Collectors;

import static com.kym.common.constant.ResponseEnum.LOGIN_FAILED;
import static com.kym.common.constant.ResponseEnum.NO_PERMISSION;

/**
 * 全局异常处理
 *
 * @author skyline
 */
@RestControllerAdvice
public class GlobalExceptionHandler {

    private static final Logger LOGGER = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    /**
     * 业务异常
     *
     * @param e 异常
     * @return 异常结果
     */
    @ExceptionHandler(value = BusinessException.class)
    @ResponseBody
    public R<?> handleBusinessException(BaseException e) {
        LOGGER.error(e.getMessage());
        return R.failed(e.getCode(), e.getMessage());
    }

    /**
     * 自定义异常
     *
     * @param e 异常
     * @return 异常结果
     */
    @ExceptionHandler(value = BaseException.class)
    @ResponseBody
    public R<Null> handleBaseException(BaseException e) {

        LOGGER.error(e.getMessage(), e);
        return R.failed();
    }


    /**
     * 登录异常
     *
     * @param e 异常
     * @return 异常结果
     */
    @ExceptionHandler(value = NotLoginException.class)
    @ResponseBody
    public R<?> handleLoginException(NotLoginException e) {

        var message = "";
        if (e.getType().equals(NotLoginException.NOT_TOKEN)) {
            message = NotLoginException.NOT_TOKEN_MESSAGE;
        } else if (e.getType().equals(NotLoginException.INVALID_TOKEN)) {
            message = NotLoginException.INVALID_TOKEN_MESSAGE;
        } else if (e.getType().equals(NotLoginException.TOKEN_TIMEOUT)) {
            message = NotLoginException.TOKEN_TIMEOUT_MESSAGE;
        } else if (e.getType().equals(NotLoginException.BE_REPLACED)) {
            message = NotLoginException.BE_REPLACED_MESSAGE;
        } else if (e.getType().equals(NotLoginException.KICK_OUT)) {
            message = NotLoginException.KICK_OUT_MESSAGE;
        } else if (e.getType().equals(NotLoginException.TOKEN_FREEZE)) {
            message = NotLoginException.TOKEN_FREEZE_MESSAGE;
        } else if (e.getType().equals(NotLoginException.NO_PREFIX)) {
            message = NotLoginException.NO_PREFIX_MESSAGE;
        } else {
            message = NotLoginException.DEFAULT_MESSAGE;
        }
        LOGGER.error("登录异常:" + message, e);
        return R.failed(LOGIN_FAILED.getCode(), message);
    }


    /**
     * 处理EN+推送返回异常
     *
     * @param e
     * @return
     */
    @ExceptionHandler(value = PlatformPushException.class)
    @ResponseBody
    public Object handleEnPushException(PlatformPushException e) {
        return e.getData();
    }


    /**
     * 校验异常处理
     *
     * @param e
     * @return
     */
    @ExceptionHandler(value = {BindException.class, ValidationException.class})
    public R handleValidatedException(Exception e) {
        String message = "";
        if (e instanceof MethodArgumentNotValidException) {
            message = ((MethodArgumentNotValidException) e).getBindingResult().getAllErrors().stream()
                    .map(ObjectError::getDefaultMessage)
                    .collect(Collectors.joining("; "));
        } else if (e instanceof ConstraintViolationException) {
            message = ((ConstraintViolationException) e).getConstraintViolations().stream()
                    .map(ConstraintViolation::getMessage)
                    .collect(Collectors.joining("; "));
        } else if (e instanceof BindException) {
            message = ((BindException) e).getAllErrors().stream().map(ObjectError::getDefaultMessage)
                    .collect(Collectors.joining("; "));
        }
        LOGGER.error(e.getMessage(), e);
        return R.failed(HttpStatus.BAD_REQUEST.value(), message);
    }

    @ExceptionHandler(value = {NotRoleException.class, NotPermissionException.class})
    public R handlerException(Exception e) {
        LOGGER.info(e.getMessage(), e);
        return R.failed(NO_PERMISSION);
    }


    /**
     * 充电业务异常处理
     *
     * @param e 异常
     * @return 异常结果
     */
    @ExceptionHandler(value = ChargeException.class)
    @ResponseBody
    public R<?> handleChargeException(ChargeException e) {
        LOGGER.error("充电业务异常：{}", e.getMessage(), e);
        return R.failed(e.getCode(), e.getMessage());
    }

    /**
     * 平台通信异常处理
     *
     * @param e 异常
     * @return 异常结果
     */
    @ExceptionHandler(value = PlatformCommunicationException.class)
    @ResponseBody
    public R<?> handlePlatformCommunicationException(PlatformCommunicationException e) {
        LOGGER.error("平台通信异常：platform={}, api={}", e.getPlatformName(), e.getApiName(), e);
        // 根据异常类型返回不同的错误信息
        if (e instanceof PlatformCommunicationException.PlatformAuthException) {
            return R.failed(503, "平台认证失败，请联系管理员");
        } else if (e instanceof PlatformCommunicationException.PlatformTimeoutException) {
            return R.failed(504, "平台响应超时，请稍后重试");
        } else if (e instanceof PlatformCommunicationException.PlatformDataFormatException) {
            return R.failed(500, "数据格式错误，请检查配置");
        }
        return R.failed(503, "外部服务不可用，请稍后重试");
    }

    /**
     * 未知异常处理（兜底）
     *
     * @param e 异常
     * @return 异常结果
     */
    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public R<?> handlerRestException(Exception e) {
        // 记录完整的堆栈信息用于排查问题
        LOGGER.error("系统未知异常：URI={}, Message={}", 
            getCurrentRequestURI(), e.getMessage(), e);
        return R.failed(HttpStatus.INTERNAL_SERVER_ERROR.value(), "系统繁忙，请稍后重试");
    }

    /**
     * 获取当前请求 URI（用于日志记录）
     */
    private String getCurrentRequestURI() {
        try {
            var requestAttributes = org.springframework.web.context.request.RequestContextHolder.currentRequestAttributes();
            if (requestAttributes instanceof org.springframework.web.context.request.ServletRequestAttributes) {
                var request = ((org.springframework.web.context.request.ServletRequestAttributes) requestAttributes).getRequest();
                return request.getRequestURI();
            }
        } catch (Exception e) {
            // 忽略异常，返回 unknown
        }
        return "unknown";
    }


}
