package com.lingniu.ingest.eventhistory;

import jakarta.servlet.http.HttpServletRequest;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import org.springframework.web.server.ResponseStatusException;
import org.springframework.web.servlet.resource.NoResourceFoundException;

import java.io.IOException;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeParseException;

/**
 * 统一 API 错误响应。
 *
 * <p>业务接口抛出的参数错误、时间格式错误和 Spring 参数绑定错误都会转成包含具体原因的
 * JSON，而不是让前端只能看到默认 400/500。这里的 timestamp 仅表示错误发生时间，
 * 按东八区展示；业务数据里的 eventTime/ingestTime 不在这里改时区。
 */
@RestControllerAdvice
public final class ApiExceptionHandler {

    private static final ZoneId DEFAULT_TIME_ZONE = ZoneId.of("Asia/Shanghai");

    @ExceptionHandler(MissingServletRequestParameterException.class)
    public ResponseEntity<ApiError> missingRequestParameter(MissingServletRequestParameterException ex,
                                                            HttpServletRequest request) {
        return error(HttpStatus.BAD_REQUEST,
                "missing required query parameter: " + ex.getParameterName(),
                request);
    }

    @ExceptionHandler(MethodArgumentTypeMismatchException.class)
    public ResponseEntity<ApiError> typeMismatch(MethodArgumentTypeMismatchException ex,
                                                 HttpServletRequest request) {
        String message = "invalid query parameter: " + ex.getName();
        if (ex.getValue() != null) {
            message += " value=" + ex.getValue();
        }
        return error(HttpStatus.BAD_REQUEST, message, request);
    }

    @ExceptionHandler(ResponseStatusException.class)
    public ResponseEntity<ApiError> responseStatus(ResponseStatusException ex,
                                                   HttpServletRequest request) {
        HttpStatus status = HttpStatus.resolve(ex.getStatusCode().value());
        if (status == null) {
            status = HttpStatus.INTERNAL_SERVER_ERROR;
        }
        String message = ex.getReason();
        if (message == null || message.isBlank()) {
            message = status.getReasonPhrase();
        }
        return error(status, message, request);
    }

    @ExceptionHandler(IllegalArgumentException.class)
    public ResponseEntity<ApiError> illegalArgument(IllegalArgumentException ex,
                                                    HttpServletRequest request) {
        return error(HttpStatus.BAD_REQUEST, safeMessage(ex, "bad request"), request);
    }

    @ExceptionHandler(DateTimeParseException.class)
    public ResponseEntity<ApiError> dateTimeParse(DateTimeParseException ex,
                                                  HttpServletRequest request) {
        return error(HttpStatus.BAD_REQUEST, "invalid date/time parameter: " + ex.getParsedString(), request);
    }

    @ExceptionHandler(NoResourceFoundException.class)
    public ResponseEntity<ApiError> noResource(NoResourceFoundException ex,
                                               HttpServletRequest request) {
        return error(HttpStatus.NOT_FOUND, "resource not found: " + request.getRequestURI(), request);
    }

    @ExceptionHandler(IOException.class)
    public ResponseEntity<ApiError> io(IOException ex,
                                       HttpServletRequest request) {
        return error(HttpStatus.SERVICE_UNAVAILABLE, safeMessage(ex, "history storage unavailable"), request);
    }

    @ExceptionHandler(Exception.class)
    public ResponseEntity<ApiError> generic(Exception ex,
                                            HttpServletRequest request) {
        // 保留异常 message 方便联调定位；底层如果没有 message，则退回通用文案。
        return error(HttpStatus.INTERNAL_SERVER_ERROR, safeMessage(ex, "internal server error"), request);
    }

    private static ResponseEntity<ApiError> error(HttpStatus status, String message, HttpServletRequest request) {
        return ResponseEntity.status(status).body(new ApiError(
                OffsetDateTime.now(DEFAULT_TIME_ZONE).toString(),
                status.value(),
                status.getReasonPhrase(),
                message,
                request.getRequestURI()));
    }

    private static String safeMessage(Exception ex, String fallback) {
        String message = ex.getMessage();
        return message == null || message.isBlank() ? fallback : message;
    }

    public record ApiError(
            String timestamp,
            int status,
            String error,
            String message,
            String path) {
    }
}
