package com.honey.honey.exception;

import com.honey.honey.service.LocalizationService;
import jakarta.validation.ConstraintViolationException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.MethodArgumentNotValidException;
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.servlet.resource.NoResourceFoundException;

@Slf4j
@RestControllerAdvice
@RequiredArgsConstructor
public class GlobalExceptionHandler {

    private final LocalizationService localizationService;

    @ExceptionHandler(BannedUserException.class)
    public ResponseEntity<ErrorResponse> handleBannedUser(BannedUserException ex) {
        log.warn("Banned user access attempt: {}", ex.getMessage());
        return ResponseEntity.status(HttpStatus.FORBIDDEN)
                .body(new ErrorResponse("BANNED", ex.getMessage()));
    }

    @ExceptionHandler(UnauthorizedException.class)
    public ResponseEntity<ErrorResponse> handleUnauthorized(UnauthorizedException ex) {
        log.warn("Unauthorized: {}", ex.getMessage());
        String localizedMessage = ex.getMessage();
        // Try to localize if message looks like a message code
        if (ex.getMessage() != null && ex.getMessage().contains(".")) {
            try {
                localizedMessage = localizationService.getMessage(ex.getMessage());
            } catch (Exception e) {
                // Use original message if localization fails
            }
        }
        return ResponseEntity.status(HttpStatus.UNAUTHORIZED)
                .body(new ErrorResponse("UNAUTHORIZED", localizedMessage));
    }

    @ExceptionHandler(GameException.class)
    public ResponseEntity<ErrorResponse> handleGameException(GameException ex) {
        log.warn("GameException: {}", ex.getUserMessage());
        String localizedMessage = ex.getUserMessage();
        // Try to localize if message looks like a message code (contains dots)
        if (ex.getUserMessage() != null && ex.getUserMessage().contains(".") && !ex.getUserMessage().contains(" ")) {
            try {
                localizedMessage = localizationService.getMessage(ex.getUserMessage());
            } catch (Exception e) {
                // Use original message if localization fails
            }
        }
        return ResponseEntity.status(HttpStatus.BAD_REQUEST)
                .body(new ErrorResponse("GAME_ERROR", localizedMessage));
    }

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<ErrorResponse> handleValidationException(MethodArgumentNotValidException ex) {
        String errorMessage = ex.getBindingResult().getFieldErrors().stream()
                .map(error -> error.getDefaultMessage())
                .findFirst()
                .orElse(localizationService.getMessage("validation.error.required", "Field"));
        log.warn("Validation error: {}", errorMessage);
        return ResponseEntity.status(HttpStatus.BAD_REQUEST)
                .body(new ErrorResponse("VALIDATION_ERROR", errorMessage));
    }

    @ExceptionHandler(ConstraintViolationException.class)
    public ResponseEntity<ErrorResponse> handleConstraintViolation(ConstraintViolationException ex) {
        String errorMessage = ex.getConstraintViolations().stream()
                .map(violation -> violation.getMessage())
                .findFirst()
                .orElse(localizationService.getMessage("validation.error.required", "Field"));
        log.warn("Constraint violation: {}", errorMessage);
        return ResponseEntity.status(HttpStatus.BAD_REQUEST)
                .body(new ErrorResponse("VALIDATION_ERROR", errorMessage));
    }

    @ExceptionHandler(MethodArgumentTypeMismatchException.class)
    public ResponseEntity<ErrorResponse> handleMethodArgumentTypeMismatch(MethodArgumentTypeMismatchException ex) {
        String paramName = ex.getName();
        String message = "telegramId".equals(paramName)
                ? "Path parameter telegramId must be a numeric Telegram user ID (e.g. 757747558), not a placeholder."
                : "Invalid value for parameter '" + paramName + "': expected " + (ex.getRequiredType() != null ? ex.getRequiredType().getSimpleName() : "valid type");
        log.warn("Invalid request parameter: {} = '{}'", paramName, ex.getValue());
        return ResponseEntity.status(HttpStatus.BAD_REQUEST)
                .body(new ErrorResponse("INVALID_PARAMETER", message));
    }

    @ExceptionHandler(NoResourceFoundException.class)
    public ResponseEntity<Void> handleNoResourceFound(NoResourceFoundException ex) {
        // Only log avatar-related missing resources without stacktrace
        String resourcePath = ex.getResourcePath();
        if (resourcePath != null && resourcePath.startsWith("/avatars/")) {
            log.debug("Avatar not found: {}", resourcePath);
        } else {
            log.debug("Resource not found: {}", resourcePath);
        }
        return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
    }

    @ExceptionHandler(Exception.class)
    public ResponseEntity<ErrorResponse> handleGeneric(Exception ex) {
        log.error("Unexpected error", ex);
        String localizedMessage = localizationService.getMessage("common.error.unknown");
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                .body(new ErrorResponse("INTERNAL_ERROR", localizedMessage));
    }
}


