package com.aps.common.exception;

import com.aps.common.util.ExceptionMessageUtil;
import com.aps.common.util.R;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.binding.BindingException;
import org.mybatis.spring.MyBatisSystemException;
import org.springframework.dao.DataAccessException;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import org.springframework.web.servlet.NoHandlerFoundException;

import java.sql.SQLException;
import java.util.Objects;

/**
 * 全局异常处理器
 * 统一处理系统中的各种异常，返回统一格式的错误信息
 */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    /**
     * 处理非法参数异常
     */
    @ExceptionHandler(IllegalArgumentException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public R<Void> handleIllegalArgumentException(IllegalArgumentException e) {
        log.error("参数校验失败:", e);
        return R.failed(500, ExceptionMessageUtil.cleanMessage(e.getMessage(), "参数校验失败"));
    }

    /**
     * 处理场景生成异常
     */
    @ExceptionHandler(SceneGenerationException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public R<Void> handleSceneGenerationException(SceneGenerationException e) {
        log.error("场景生成异常:", e);
        return R.failed(500, ExceptionMessageUtil.cleanMessage(e.getMessage(), "场景生成失败，请检查场景数据后重试"));
    }

    /**
     * 处理业务异常
     */
    @ExceptionHandler(BusinessException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public R<Void> handleBusinessException(BusinessException e) {
        log.error("业务异常:", e);
        return R.failed(500, ExceptionMessageUtil.cleanMessage(e.getMessage(), "业务处理失败，请稍后重试"));
    }

    /**
     * 处理自定义业务异常
     */
    @ExceptionHandler(RuntimeException.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public R<Void> handleRuntimeException(RuntimeException e) {
        log.error("运行时异常:", e);
        return R.failed(500, ExceptionMessageUtil.toClientMessage(e, "系统处理失败，请稍后重试或联系管理员"));
    }

    /**
     * 处理MyBatis绑定异常
     */
    @ExceptionHandler(BindingException.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public R<Void> handleBindingException(BindingException e) {
        log.error("MyBatis绑定异常:", e);
        return R.failed(500, "数据绑定异常，请联系管理员");
    }

    /**
     * 处理MyBatis系统异常
     */
    @ExceptionHandler(MyBatisSystemException.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public R<Void> handleMyBatisSystemException(MyBatisSystemException e) {
        log.error("MyBatis系统异常:", e);
        Throwable cause = e.getCause();
        if (cause != null && cause.getMessage().contains("ORA-17004")) {
            return R.failed(500, "数据库列类型无效，请检查查询参数是否正确");
        }
        return R.failed(500, "数据库操作异常，请联系管理员");
    }

    /**
     * 处理SQL异常
     */
    @ExceptionHandler(SQLException.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public R<Void> handleSQLException(SQLException e) {
        log.error("SQL异常:", e);
        return R.failed(500, "数据库访问异常，请联系管理员");
    }

    /**
     * 处理数据访问异常
     */
    @ExceptionHandler(DataAccessException.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public R<Void> handleDataAccessException(DataAccessException e) {
        log.error("数据访问异常:", e);
        return R.failed(500, "数据访问异常，请联系管理员");
    }

    /**
     * 处理参数验证异常(MethodArgumentNotValidException)
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public R<Void> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
        log.error("参数验证异常:", e);
        FieldError fieldError = e.getBindingResult().getFieldError();
        if (fieldError != null) {
            return R.failed(400, ExceptionMessageUtil.cleanMessage(
                    Objects.requireNonNull(fieldError.getDefaultMessage()), "参数验证失败"));
        }
        return R.failed(400, "参数验证失败");
    }

    /**
     * 处理参数绑定异常(BindException)
     */
    @ExceptionHandler(BindException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public R<Void> handleBindException(BindException e) {
        log.error("参数绑定异常:", e);
        FieldError fieldError = e.getBindingResult().getFieldError();
        if (fieldError != null) {
            return R.failed(500, ExceptionMessageUtil.cleanMessage(
                    Objects.requireNonNull(fieldError.getDefaultMessage()), "参数绑定失败"));
        }
        return R.failed(500, "参数绑定失败");
    }

    /**
     * 处理请求参数缺失异常
     */
    @ExceptionHandler(MissingServletRequestParameterException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public R<Void> handleMissingServletRequestParameterException(MissingServletRequestParameterException e) {
        log.error("请求参数缺失:", e);
        return R.failed(500, "缺少必要参数: " + e.getParameterName());
    }

    /**
     * 处理参数类型不匹配异常
     */
    @ExceptionHandler(MethodArgumentTypeMismatchException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public R<Void> handleMethodArgumentTypeMismatchException(MethodArgumentTypeMismatchException e) {
        log.error("参数类型不匹配:", e);
        return R.failed(500, "参数类型不匹配: " + e.getName());
    }

    /**
     * 处理HTTP消息不可读异常
     */
    @ExceptionHandler(HttpMessageNotReadableException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public R<Void> handleHttpMessageNotReadableException(HttpMessageNotReadableException e) {
        log.error("HTTP消息不可读:", e);
        return R.failed(500, "请求体格式错误");
    }

    /**
     * 处理HTTP请求方法不支持异常
     */
    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    @ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED)
    public R<Void> handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e) {
        log.error("HTTP请求方法不支持:", e);
        return R.failed(405, "请求方法不支持: " + e.getMethod());
    }

    /**
     * 处理HTTP媒体类型不支持异常
     */
    @ExceptionHandler(HttpMediaTypeNotSupportedException.class)
    @ResponseStatus(HttpStatus.UNSUPPORTED_MEDIA_TYPE)
    public R<Void> handleHttpMediaTypeNotSupportedException(HttpMediaTypeNotSupportedException e) {
        log.error("HTTP媒体类型不支持:", e);
        return R.failed(415, "媒体类型不支持: " + e.getContentType());
    }

    /**
     * 处理404异常
     */
    @ExceptionHandler(NoHandlerFoundException.class)
    @ResponseStatus(HttpStatus.NOT_FOUND)
    public R<Void> handleNoHandlerFoundException(NoHandlerFoundException e) {
        log.error("404异常:", e);
        return R.failed(404, "请求的资源不存在: " + e.getRequestURL());
    }

    /**
     * 处理其他未捕获的异常
     */
    @ExceptionHandler(Exception.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public R<Void> handleException(Exception e) {
        log.error("未知异常:", e);
        return R.failed(500, "系统异常，请联系管理员");
    }
}
