using Microsoft.Data.SqlClient;

namespace OASystem.API.Middlewares
{
    /// <summary>
    /// 全局异常捕获中间件
    /// </summary>
    public class ExceptionHandlingMiddleware
    {
        private readonly RequestDelegate _next;  // 用来处理上下文请求
        private readonly ILogger<ExceptionHandlingMiddleware> _logger;
        private readonly SqlSugarClient _db;

        /// <summary>
        /// 初始化
        /// </summary>
        /// <param name="next"></param>
        /// <param name="logger"></param>
        /// <param name="db"></param>
        public ExceptionHandlingMiddleware(RequestDelegate next, ILogger<ExceptionHandlingMiddleware> logger, SqlSugarClient db)
        {
            _next = next;
            _logger = logger;
            _db = db;
        }

        /// <summary>
        /// 执行中间件
        /// </summary>
        /// <param name="httpContext"></param>
        /// <param name="db"></param>
        /// <returns></returns>
        public async Task InvokeAsync(HttpContext httpContext, SqlSugarClient db)
        {
            try
            {
                await _next(httpContext); //要么在中间件中处理,要么被传递到下一个中间件中去
            }
            catch (Exception ex)
            {
                await HandleExceptionAsync(httpContext, ex, db); // 捕获异常了 在HandleExceptionAsync中处理
            }
        }

        /// <summary>
        /// 自定义全局异常处理方法
        /// </summary>
        /// <param name="context"></param>
        /// <param name="exception"></param>
        /// <param name="db"></param>
        /// <returns></returns>
        private async Task HandleExceptionAsync(HttpContext context, Exception exception, SqlSugarClient db)
        {
            if (db.Ado != null && db.Ado.Transaction != null)
            {
                try
                {
                    db.Ado.RollbackTran();
                }
                catch (Exception ex)
                {
                    _logger.LogError("Error rolling back transaction: {ErrorMessage}", ex.Message);
                }
            }

            // 检查响应是否已开始
            if (!context.Response.HasStarted)
            {
                context.Response.ContentType = "application/json"; // 设置响应内容类型为 JSON
                var response = context.Response;
                var errorResponse = new JsonView
                {
                    Code = StatusCodes.Status500InternalServerError,
                    Data = ""
                };

                // 根据异常类型设置不同的响应状态码和消息
                switch (exception)
                {
                    case SqlException sqlEx when sqlEx.Number == -2:
                        response.StatusCode = StatusCodes.Status503ServiceUnavailable;
                        errorResponse.Msg = "数据库连接超时,请稍后重试。";
                        break;
                    case SqlException sqlEx when sqlEx.Number == -4:
                        response.StatusCode = StatusCodes.Status503ServiceUnavailable;
                        errorResponse.Msg = "数据库连接池耗尽,请稍后重试。";
                        break;
                    case ApplicationException ex when ex.Message.Contains("Invalid token"):
                        response.StatusCode = StatusCodes.Status403Forbidden;
                        errorResponse.Msg = ex.Message;
                        break;
                    case ApplicationException ex:
                        response.StatusCode = StatusCodes.Status400BadRequest;
                        errorResponse.Msg = ex.Message;
                        break;
                    case KeyNotFoundException ex:
                        response.StatusCode = StatusCodes.Status404NotFound;
                        errorResponse.Msg = ex.Message;
                        break;
                    case SqlSugarException ex:
                        response.StatusCode = ex.Message.Contains("timeout")
                            ? StatusCodes.Status503ServiceUnavailable
                            : StatusCodes.Status500InternalServerError;
                        errorResponse.Msg = ex.Message.Contains("timeout")
                            ? "数据库连接超时,请稍后重试。"
                            : ex.Message;
                        break;
                    default:
                        response.StatusCode = StatusCodes.Status500InternalServerError;
                        errorResponse.Msg = "服务器内部错误"; // 不直接暴露异常详细信息
                        break;
                }

                _logger.LogError(exception, "An exception occurred."); // 记录异常详细信息
                var result = JsonConvert.SerializeObject(errorResponse);
                await context.Response.WriteAsync(result); // 将错误响应写入客户端
            }
            else
            {
                // 如果响应已开始,记录日志但不做进一步处理
                _logger.LogError(exception, "An exception occurred after response started.");
            }
        }
    }
}