InvalidRequestException.java

package com.smartsupplypro.inventory.exception;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Enterprise exception for client request validation failures.
 * 
 * <p>Enforces API contract compliance through parameter validation, business rule
 * verification, and data integrity constraints for reliable service operations.
 * 
 * <p>Key integrations: Request validation, Service layer checks, Controller parameters.
 * 
 * @author Smart Supply Pro Development Team
 * @version 1.0.0
 * @since 1.0.0
 * @see GlobalExceptionHandler
 */
public class InvalidRequestException extends RuntimeException {
    
    private final ValidationSeverity severity;
    private final String validationCode;
    private final Map<String, String> fieldErrors;
    private final List<String> generalErrors;

    /**
     * Creates invalid request exception with validation details.
     * 
     * @param message specific validation failure description
     */
    public InvalidRequestException(String message) { 
        super(message);
        this.severity = ValidationSeverity.MEDIUM;
        this.validationCode = "INVALID_REQUEST";
        this.fieldErrors = new HashMap<>();
        this.generalErrors = new ArrayList<>();
    }

    /**
     * Creates invalid request exception with detailed validation context.
     * 
     * @param message specific validation failure description
     * @param severity validation failure severity level
     * @param validationCode specific validation code for client handling
     */
    public InvalidRequestException(String message, ValidationSeverity severity, String validationCode) {
        super(message);
        this.severity = severity;
        this.validationCode = validationCode;
        this.fieldErrors = new HashMap<>();
        this.generalErrors = new ArrayList<>();
    }

    /**
     * Creates invalid request exception with field-specific errors.
     * 
     * @param message general validation failure description
     * @param fieldErrors map of field names to specific error messages
     */
    public InvalidRequestException(String message, Map<String, String> fieldErrors) {
        super(message);
        this.severity = ValidationSeverity.MEDIUM;
        this.validationCode = "FIELD_VALIDATION_FAILED";
        this.fieldErrors = fieldErrors != null ? new HashMap<>(fieldErrors) : new HashMap<>();
        this.generalErrors = new ArrayList<>();
    }

    // Enterprise utility methods for enhanced validation handling

    /**
     * Gets the severity level of this validation failure.
     * 
     * @return validation severity classification
     */
    public ValidationSeverity getSeverity() {
        return severity;
    }

    /**
     * Gets the specific validation code for client error handling.
     * 
     * @return validation code identifier
     */
    public String getValidationCode() {
        return validationCode;
    }

    /**
     * Gets field-specific validation errors.
     * 
     * @return immutable map of field errors
     */
    public Map<String, String> getFieldErrors() {
        return Map.copyOf(fieldErrors);
    }

    /**
     * Gets general validation errors not tied to specific fields.
     * 
     * @return immutable list of general errors
     */
    public List<String> getGeneralErrors() {
        return List.copyOf(generalErrors);
    }

    /**
     * Checks if this exception has field-specific validation errors.
     * 
     * @return true if field errors are present
     */
    public boolean hasFieldErrors() {
        return !fieldErrors.isEmpty();
    }

    /**
     * Checks if this exception has general validation errors.
     * 
     * @return true if general errors are present
     */
    public boolean hasGeneralErrors() {
        return !generalErrors.isEmpty();
    }

    /**
     * Gets the total number of validation errors.
     * 
     * @return sum of field and general errors
     */
    public int getErrorCount() {
        return fieldErrors.size() + generalErrors.size();
    }

    /**
     * Checks if this is a critical validation failure requiring immediate attention.
     * 
     * @return true if severity is CRITICAL
     */
    public boolean isCritical() {
        return severity == ValidationSeverity.CRITICAL;
    }

    /**
     * Creates a structured error response for API clients.
     * 
     * @return map containing validation details for client consumption
     */
    public Map<String, Object> getValidationDetails() {
        Map<String, Object> details = new HashMap<>();
        details.put("validationCode", validationCode);
        details.put("severity", severity.name());
        details.put("message", getMessage());
        
        if (hasFieldErrors()) {
            details.put("fieldErrors", fieldErrors);
        }
        
        if (hasGeneralErrors()) {
            details.put("generalErrors", generalErrors);
        }
        
        details.put("errorCount", getErrorCount());
        return details;
    }

    // Static factory methods for common validation scenarios

    /**
     * Creates exception for required field validation failures.
     * 
     * @param fieldName the missing required field
     * @return configured exception instance
     */
    public static InvalidRequestException requiredField(String fieldName) {
        Map<String, String> fieldErrors = Map.of(fieldName, "This field is required");
        return new InvalidRequestException(
            "Required field missing: " + fieldName, 
            fieldErrors
        );
    }

    /**
     * Creates exception for invalid format validation failures.
     * 
     * @param fieldName the field with invalid format
     * @param expectedFormat description of expected format
     * @return configured exception instance
     */
    public static InvalidRequestException invalidFormat(String fieldName, String expectedFormat) {
        Map<String, String> fieldErrors = Map.of(fieldName, "Invalid format. Expected: " + expectedFormat);
        return new InvalidRequestException(
            "Invalid format for field: " + fieldName, 
            fieldErrors
        );
    }

    /**
     * Creates exception for value range validation failures.
     * 
     * @param fieldName the field with out-of-range value
     * @param minValue minimum allowed value
     * @param maxValue maximum allowed value
     * @return configured exception instance
     */
    public static InvalidRequestException valueOutOfRange(String fieldName, Object minValue, Object maxValue) {
        Map<String, String> fieldErrors = Map.of(fieldName, 
            String.format("Value must be between %s and %s", minValue, maxValue));
        return new InvalidRequestException(
            "Value out of range for field: " + fieldName, 
            fieldErrors
        );
    }

    /**
     * Creates exception for business rule validation failures.
     * 
     * @param businessRule description of violated business rule
     * @return configured exception instance
     */
    public static InvalidRequestException businessRuleViolation(String businessRule) {
        return new InvalidRequestException(
            "Business rule violation: " + businessRule,
            ValidationSeverity.HIGH,
            "BUSINESS_RULE_VIOLATION"
        );
    }

    /**
     * Creates exception for critical security validation failures.
     * 
     * @param securityIssue description of security validation failure
     * @return configured exception instance with CRITICAL severity
     */
    public static InvalidRequestException securityViolation(String securityIssue) {
        return new InvalidRequestException(
            "Security validation failed: " + securityIssue,
            ValidationSeverity.CRITICAL,
            "SECURITY_VIOLATION"
        );
    }

    // Nested enum for validation severity classification
    public enum ValidationSeverity {
        LOW,      // Minor validation issues, warnings
        MEDIUM,   // Standard validation failures
        HIGH,     // Business rule violations
        CRITICAL  // Security or data integrity issues
    }
}