/*
 * Copyright (c) 2025 SimcuTeam. All rights reserved.
 * 遵循 MIT 许可证。
 */

package simcu::simapi.middlewares

import soulsoft_web_http.*
import soulsoft_extensions_logging.*
import simcu::serialization.*
import simcu::simapi.communications.*
import simcu::simapi.exceptions.*
import simcu::simapi.configurations.*
import simcu::simapi.helpers.*

/**
 * 异常处理中间件：全异常捕获，统一输出 HTTP 200 + JSON 响应。
 */
public class SimApiExceptionMiddleware <: IMiddleware {
    private let _options: SimApiOptions
    private let _logger: ILogger

    public init(options: SimApiOptions, loggerFactory: ILoggerFactory) {
        _options = options
        _logger = loggerFactory.createLogger("SimApi.ExceptionMiddleware")
    }

    /**
     * 中间件入口（IMiddleware 风格）。
     */
    public func invoke(context: HttpContext, next: RequestDelegate): Unit {
        try {
            // 透传 Query-Id 请求头
            if (let Some(queryId) <- context.request.headers.get("Query-Id")) {
                context.response.headers.add("Query-Id", queryId)
            }
            next(context)
            // 若响应未开始且状态码不在跳过列表，则视为业务错误
            if (!context.response.hasStarted) {
                let code = Int64(context.response.statusCode)
                if (!_options.simApiExceptionOptions.skipStatusCodes.contains(code)) {
                    throw SimApiException(code)
                }
            }
        } catch (ex: Exception) {
            let response = buildResponse(ex, context)
            if (!context.response.hasStarted) {
                context.response.statusCode = 200
                context.response.contentType = "application/json; charset=utf-8"
                SimApiResponseWriter.write(context, responseJson(response))
            }
        }
    }

    private func buildResponse(ex: Exception, context: HttpContext): SimApiBaseResponse {
        if (let simEx: SimApiException <- ex) {
            let message = if (simEx.message.isEmpty()) {
                SimApiBaseResponse.getDefaultMessage(simEx.code)
            } else {
                simEx.message
            }
            var response = SimApiBaseResponse(simEx.code, message)
            if (context.response.statusCode == 404) {
                response.message = "接口不存在"
            }
            return response
        }
        _logger.error(EventId(0), ex, ex.message)
        return SimApiBaseResponse(500)
    }

    private func responseJson(response: SimApiBaseResponse): String {
        JsonSerializer.serialize(response)
    }
}
