ErrorResponse.java

package com.smartsupplypro.inventory.exception.dto;

import java.time.Instant;
import java.util.concurrent.ThreadLocalRandom;

import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;

/**
 * Standardized error response builder for enterprise REST API consistency.
 *
 * <p>Provides immutable error response structure with correlation tracking,
 * ISO-8601 timestamps, and normalized HTTP status token mapping for reliable
 * client-side error handling across all API endpoints.
 *
 * <p><strong>Response Structure</strong>:
 * <pre>
 * {
 *   "error": "bad_request",
 *   "message": "Validation failed: email is required",
 *   "timestamp": "2025-11-14T12:34:56.789Z",
 *   "correlationId": "SSP-1700123456789-4523"
 * }
 * </pre>
 *
 * <p><strong>Usage Example</strong>:
 * <pre>
 * return ErrorResponse.builder()
 *     .status(HttpStatus.BAD_REQUEST)
 *     .message("Invalid email format")
 *     .build();
 * </pre>
 *
 * @author Smart Supply Pro Development Team
 * @version 1.0.0
 * @since 1.0.0
 */
public class ErrorResponse {

    private final String error;
    private final String message;
    private final String timestamp;
    private final String correlationId;

    private ErrorResponse(Builder builder) {
        this.error = builder.error;
        this.message = builder.message;
        this.timestamp = builder.timestamp;
        this.correlationId = builder.correlationId;
    }

    /**
     * Creates a new builder instance for fluent error response construction.
     *
     * @return new ErrorResponse builder
     */
    public static Builder builder() {
        return new Builder();
    }

    /**
     * Fluent builder for ErrorResponse construction with validation.
     * @author Smart Supply Pro Development Team
     */
    public static class Builder {
        private String error;
        private String message;
        private String timestamp;
        private String correlationId;
        private HttpStatus status;

        /**
         * Sets HTTP status and derives normalized error token.
         *
         * @param status HTTP status code
         * @return this builder for chaining
         */
        public Builder status(HttpStatus status) {
            this.status = status;
            this.error = status.name().toLowerCase();
            return this;
        }

        /**
         * Sets human-readable error message with fallback to HTTP reason phrase.
         *
         * @param message descriptive error message
         * @return this builder for chaining
         */
        public Builder message(String message) {
            this.message = (message == null || message.isBlank()) 
                ? (status != null ? status.getReasonPhrase() : "Unknown error")
                : message;
            return this;
        }

        /**
         * Builds ResponseEntity with JSON content type and standardized structure.
         *
         * @return complete HTTP response entity with error payload
         */
        public ResponseEntity<ErrorResponse> build() {
            // Auto-generate timestamp and correlation ID if not provided
            if (this.timestamp == null) {
                this.timestamp = Instant.now().toString();
            }
            if (this.correlationId == null) {
                this.correlationId = generateCorrelationId();
            }
            
            ErrorResponse response = new ErrorResponse(this);
            return ResponseEntity.status(status)
                    .contentType(MediaType.APPLICATION_JSON)
                    .body(response);
        }

        /**
         * Generates unique correlation ID for request tracking.
         *
         * @return formatted correlation ID (SSP-{timestamp}-{random})
         */
        private String generateCorrelationId() {
            return "SSP-" + System.currentTimeMillis() + "-" + 
                   ThreadLocalRandom.current().nextInt(1000, 9999);
        }
    }

    // Getters for JSON serialization
    public String getError() { return error; }
    public String getMessage() { return message; }
    public String getTimestamp() { return timestamp; }
    public String getCorrelationId() { return correlationId; }
}