# Book.java

    package com.university.bookstore.model;

    import java.time.Year;
    import java.util.Objects;
    import java.util.regex.Pattern;

    /**
     * Represents an immutable book in the bookstore inventory.
     * Books are uniquely identified by their ISBN.
     *
     * <p>This class is immutable and thread-safe. All fields are validated
     * during construction to ensure data integrity.</p>
     *
     * @author Navid Mohaghegh
     * @version 1.0
     * @since 2024-09-15
     */
    public final class Book implements Comparable<Book> {

        private static final Pattern ISBN_13_PATTERN = Pattern.compile("^\\d{13}$");
        private static final Pattern ISBN_10_PATTERN = Pattern.compile("^\\d{9}[\\dX]$");
        private static final int MIN_YEAR = 1450; // Invention of printing press

        private final String isbn;
        private final String title;
        private final String author;
        private final double price;
        private final int year;

        /**
         * Creates a new Book with validation.
         *
         * @param isbn the International Standard Book Number (10 or 13 digits)
         * @param title the book title (non-null, non-blank)
         * @param author the primary author (non-null, non-blank)
         * @param price the price in dollars (non-negative)
         * @param year the publication year (1450 to current year + 1)
         * @throws IllegalArgumentException if any parameter is invalid
         * @throws NullPointerException if any string parameter is null
         */
        public Book(String isbn, String title, String author, double price, int year) {
            this.isbn = validateIsbn(isbn);
            this.title = validateStringField(title, "Title");
            this.author = validateStringField(author, "Author");
            this.price = validatePrice(price);
            this.year = validateYear(year);
        }

        private String validateIsbn(String isbn) {
            if (isbn == null) {
                throw new NullPointerException("ISBN cannot be null");
            }

            String cleaned = isbn.replaceAll("-", "").trim();

            if (!ISBN_10_PATTERN.matcher(cleaned).matches() &&
                !ISBN_13_PATTERN.matcher(cleaned).matches()) {
                throw new IllegalArgumentException(
                    "ISBN must be 10 or 13 digits. Provided: " + isbn);
            }

            return cleaned;
        }

        private String validateStringField(String value, String fieldName) {
            if (value == null) {
                throw new NullPointerException(fieldName + " cannot be null");
            }
            if (value.trim().isEmpty()) {
                throw new IllegalArgumentException(fieldName + " cannot be blank");
            }
            return value.trim();
        }

        private double validatePrice(double price) {
            if (price < 0.0) {
                throw new IllegalArgumentException(
                    "Price cannot be negative. Provided: " + price);
            }
            if (Double.isNaN(price) || Double.isInfinite(price)) {
                throw new IllegalArgumentException(
                    "Price must be a valid number. Provided: " + price);
            }
            return price;
        }

        private int validateYear(int year) {
            int currentYear = Year.now().getValue();
            if (year < MIN_YEAR || year > currentYear + 1) {
                throw new IllegalArgumentException(
                    String.format("Year must be between %d and %d. Provided: %d",
                        MIN_YEAR, currentYear + 1, year));
            }
            return year;
        }

        /**
         * Gets the ISBN of this book.
         * @return the ISBN (10 or 13 digits)
         */
        public String getIsbn() {
            return isbn;
        }

        /**
         * Gets the title of this book.
         * @return the book title
         */
        public String getTitle() {
            return title;
        }

        /**
         * Gets the author of this book.
         * @return the author name
         */
        public String getAuthor() {
            return author;
        }

        /**
         * Gets the price of this book.
         * @return the price in dollars
         */
        public double getPrice() {
            return price;
        }

        /**
         * Gets the publication year of this book.
         * @return the publication year
         */
        public int getYear() {
            return year;
        }

        /**
         * Compares this book with another book based on title (alphabetical order).
         *
         * @param other the book to compare with
         * @return negative if this book comes before, positive if after, 0 if equal
         */
        @Override
        public int compareTo(Book other) {
            if (other == null) {
                throw new NullPointerException("Cannot compare to null Book");
            }
            return this.title.compareToIgnoreCase(other.title);
        }

        /**
         * Checks if this book is equal to another object.
         * Books are considered equal if they have the same ISBN.
         *
         * @param obj the object to compare with
         * @return true if the objects are equal (same ISBN), false otherwise
         */
        @Override
        public boolean equals(Object obj) {
            if (this == obj) return true;
            if (!(obj instanceof Book)) return false;
            Book other = (Book) obj;
            return isbn.equals(other.isbn);
        }

        /**
         * Generates hash code based on ISBN.
         *
         * @return hash code of the ISBN
         */
        @Override
        public int hashCode() {
            return Objects.hash(isbn);
        }

        /**
         * Returns a human-readable string representation of this book.
         *
         * @return formatted string with book details
         */
        @Override
        public String toString() {
            return String.format("Book[ISBN=%s, Title='%s', Author='%s', Price=$%.2f, Year=%d]",
                isbn, title, author, price, year);
        }
    }