# DiscountRequest.java

    package com.university.bookstore.chain;

    import java.util.Objects;

    import com.university.bookstore.model.Material;

    /**
     * Request object for discount approval in the Chain of Responsibility pattern.
     * Contains all information needed to process a discount request.
     *
     * @author Navid Mohaghegh
     * @version 3.0
     * @since 2024-09-15
     */
    public class DiscountRequest {

        private final Material material;
        private final double requestedDiscount;
        private final String customerId;
        private final String reason;
        private boolean approved;
        private String approvedBy;
        private String rejectionReason;
        private final long timestamp;

        /**
         * Creates a new discount request.
         *
         * @param material the material for which discount is requested
         * @param requestedDiscount the requested discount rate (0.0 to 1.0)
         * @param customerId the customer requesting the discount
         * @param reason the reason for the discount request
         * @throws IllegalArgumentException if parameters are invalid
         */
        public DiscountRequest(Material material, double requestedDiscount,
                              String customerId, String reason) {
            this.material = Objects.requireNonNull(material, "Material cannot be null");
            this.requestedDiscount = Math.max(0.0, Math.min(1.0, requestedDiscount));
            this.customerId = Objects.requireNonNull(customerId, "Customer ID cannot be null");
            this.reason = Objects.requireNonNull(reason, "Reason cannot be null");
            this.approved = false;
            this.timestamp = System.currentTimeMillis();
        }

        /**
         * Gets the material for which discount is requested.
         *
         * @return the material
         */
        public Material getMaterial() {
            return material;
        }

        /**
         * Gets the requested discount rate.
         *
         * @return the discount rate (0.0 to 1.0)
         */
        public double getRequestedDiscount() {
            return requestedDiscount;
        }

        /**
         * Gets the requested discount percentage.
         *
         * @return the discount percentage (0.0 to 100.0)
         */
        public double getRequestedDiscountPercentage() {
            return requestedDiscount * 100.0;
        }

        /**
         * Gets the customer ID.
         *
         * @return the customer ID
         */
        public String getCustomerId() {
            return customerId;
        }

        /**
         * Gets the reason for the discount request.
         *
         * @return the reason
         */
        public String getReason() {
            return reason;
        }

        /**
         * Checks if the request is approved.
         *
         * @return true if approved
         */
        public boolean isApproved() {
            return approved;
        }

        /**
         * Sets the approval status.
         *
         * @param approved the approval status
         */
        public void setApproved(boolean approved) {
            this.approved = approved;
        }

        /**
         * Gets who approved the request.
         *
         * @return the approver name
         */
        public String getApprovedBy() {
            return approvedBy;
        }

        /**
         * Sets who approved the request.
         *
         * @param approvedBy the approver name
         */
        public void setApprovedBy(String approvedBy) {
            this.approvedBy = approvedBy;
        }

        /**
         * Gets the rejection reason.
         *
         * @return the rejection reason
         */
        public String getRejectionReason() {
            return rejectionReason;
        }

        /**
         * Sets the rejection reason.
         *
         * @param rejectionReason the rejection reason
         */
        public void setRejectionReason(String rejectionReason) {
            this.rejectionReason = rejectionReason;
        }

        /**
         * Gets the request timestamp.
         *
         * @return the timestamp in milliseconds
         */
        public long getTimestamp() {
            return timestamp;
        }

        /**
         * Calculates the discounted price if approved.
         *
         * @return the discounted price
         */
        public double getDiscountedPrice() {
            if (approved) {
                return material.getPrice() * (1.0 - requestedDiscount);
            }
            return material.getPrice();
        }

        /**
         * Calculates the savings amount if approved.
         *
         * @return the savings amount
         */
        public double getSavingsAmount() {
            if (approved) {
                return material.getPrice() * requestedDiscount;
            }
            return 0.0;
        }

        /**
         * Gets a summary of the discount request.
         *
         * @return the request summary
         */
        public String getSummary() {
            return String.format("Discount Request: %s for %s (%.1f%%) - %s",
                material.getTitle(), customerId, getRequestedDiscountPercentage(), reason);
        }

        @Override
        public boolean equals(Object obj) {
            if (this == obj) return true;
            if (obj == null || getClass() != obj.getClass()) return false;

            DiscountRequest that = (DiscountRequest) obj;
            return Double.compare(that.requestedDiscount, requestedDiscount) == 0 &&
                   approved == that.approved &&
                   timestamp == that.timestamp &&
                   Objects.equals(material, that.material) &&
                   Objects.equals(customerId, that.customerId) &&
                   Objects.equals(reason, that.reason) &&
                   Objects.equals(approvedBy, that.approvedBy) &&
                   Objects.equals(rejectionReason, that.rejectionReason);
        }

        @Override
        public int hashCode() {
            return Objects.hash(material, requestedDiscount, customerId, reason,
                              approved, approvedBy, rejectionReason, timestamp);
        }

        @Override
        public String toString() {
            return String.format("DiscountRequest[%s, %.1f%%, %s, %s, Approved=%s]",
                material.getTitle(), getRequestedDiscountPercentage(), customerId, reason, approved);
        }
    }