package com.mosquito.project.exception;

import com.mosquito.project.dto.ApiResponse;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.context.request.WebRequest;
import org.springframework.validation.FieldError;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;

@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(BusinessException.class)
    public ResponseEntity<ApiResponse<Void>> handleBusinessException(BusinessException ex, WebRequest request) {
        String path = extractPath(request);
        Map<String, Object> details = new HashMap<>();
        details.put("code", ex.getErrorCode());
        details.put("path", path);
        if (ex.getDetails() != null) {
            details.putAll(ex.getDetails());
        }

        ApiResponse<Void> response = buildError(ex.getStatus(), ex.getMessage(), ex.getErrorCode(), details);
        return new ResponseEntity<>(response, ex.getStatus());
    }

    @ExceptionHandler(ResourceNotFoundException.class)
    public ResponseEntity<ApiResponse<Void>> handleResourceNotFoundException(ResourceNotFoundException ex, WebRequest request) {
        Map<String, Object> details = new HashMap<>();
        details.put("resourceType", ex.getResourceType());
        details.put("resourceId", ex.getResourceId());
        details.put("path", extractPath(request));

        ApiResponse<Void> response = buildError(HttpStatus.NOT_FOUND, ex.getMessage(), null, details);
        return new ResponseEntity<>(response, HttpStatus.NOT_FOUND);
    }

    @ExceptionHandler(ValidationException.class)
    public ResponseEntity<ApiResponse<Void>> handleValidationException(ValidationException ex, WebRequest request) {
        Map<String, Object> details = new HashMap<>();
        details.put("path", extractPath(request));
        if (ex.getErrors() != null) {
            details.putAll(ex.getErrors());
        }

        ApiResponse<Void> response = buildError(HttpStatus.BAD_REQUEST, ex.getMessage(), null, details);
        return new ResponseEntity<>(response, HttpStatus.BAD_REQUEST);
    }

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<ApiResponse<Void>> handleMethodArgumentNotValid(MethodArgumentNotValidException ex, WebRequest request) {
        Map<String, Object> details = new HashMap<>();
        details.put("path", extractPath(request));
        Map<String, String> fieldErrors = new HashMap<>();
        for (FieldError error : ex.getBindingResult().getFieldErrors()) {
            fieldErrors.put(error.getField(), error.getDefaultMessage());
        }
        details.put("fieldErrors", fieldErrors);

        ApiResponse<Void> response = buildError(HttpStatus.BAD_REQUEST, "参数校验失败", null, details);
        return new ResponseEntity<>(response, HttpStatus.BAD_REQUEST);
    }

    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    public ResponseEntity<ApiResponse<Void>> handleMethodNotSupported(HttpRequestMethodNotSupportedException ex, WebRequest request) {
        Map<String, Object> details = new HashMap<>();
        details.put("path", extractPath(request));
        details.put("method", ex.getMethod());
        details.put("supported", ex.getSupportedHttpMethods());

        ApiResponse<Void> response = buildError(HttpStatus.METHOD_NOT_ALLOWED, ex.getMessage(), null, details);
        return new ResponseEntity<>(response, HttpStatus.METHOD_NOT_ALLOWED);
    }

    @ExceptionHandler(Exception.class)
    public ResponseEntity<ApiResponse<Void>> handleGenericException(Exception ex, WebRequest request) {
        Map<String, Object> details = new HashMap<>();
        details.put("exception", ex.getClass().getSimpleName());
        details.put("path", extractPath(request));

        ApiResponse<Void> response = buildError(HttpStatus.INTERNAL_SERVER_ERROR, "An unexpected error occurred", null, details);
        return new ResponseEntity<>(response, HttpStatus.INTERNAL_SERVER_ERROR);
    }

    private ApiResponse<Void> buildError(HttpStatus status, String message, String code, Map<String, Object> details) {
        ApiResponse.Error error = new ApiResponse.Error(message, details);
        error.setCode(code);
        return ApiResponse.<Void>builder()
            .code(status.value())
            .message(message)
            .error(error)
            .timestamp(LocalDateTime.now())
            .build();
    }

    private String extractPath(WebRequest request) {
        return request.getDescription(false).replace("uri=", "");
    }
}
