Product.java

package com.ctrlbuy.webshop.entity;

import jakarta.persistence.*;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.ToString;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

/**
 * Product Entity - Railway-optimerad med fullständig ProductService kompatibilitet
 * ✅ UPPDATERAD: Alla stock methods, Lombok integration, och business logic
 */
@Entity
@Table(name = "products", indexes = {
        @Index(name = "idx_product_category", columnList = "category"),
        @Index(name = "idx_product_active", columnList = "isActive"),
        @Index(name = "idx_product_sale", columnList = "isOnSale"),
        @Index(name = "idx_product_featured", columnList = "isFeatured"),
        @Index(name = "idx_product_price", columnList = "price"),
        @Index(name = "idx_product_created", columnList = "createdAt")
})
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@ToString(exclude = {"productImages"}) // Undvik lazy loading i toString
public class Product {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false, length = 255)
    private String name;

    @Column(length = 2000)
    private String description;

    @Column(nullable = false, precision = 10)
    private BigDecimal price;

    @Column(nullable = false, length = 100)
    private String category;

    // ============================
    // STOCK FIELDS - Multiple compatibility options
    // ============================

    /**
     * Primary stock field - används av ProductService
     */
    @Column(nullable = false, name = "stockQuantity")
    @Builder.Default
    private Integer stockQuantity = 0;

    // ============================
    // PRODUCT DETAILS
    // ============================

    @Column(name = "imageUrl", length = 500)
    private String imageUrl;

    @Column(length = 100)
    private String brand;

    @Column(length = 100)
    private String model;

    @Column(length = 50)
    private String color;

    @Column(length = 100)
    private String sku;

    @Column(length = 100)
    private String barcode;

    @Column(length = 200)
    private String dimensions;

    @Column(precision = 8)
    private Float weight;

    @Column(name = "originCountry", length = 100)
    private String originCountry;

    // ============================
    // PRICING FIELDS
    // ============================

    @Column(precision = 10, name = "costPrice")
    private BigDecimal costPrice;

    @Column(precision = 10, name = "originalPrice")
    private BigDecimal originalPrice;

    @Column(precision = 10, name = "salePrice")
    private BigDecimal salePrice;

    @Column(precision = 5, name = "discountPercentage")
    private BigDecimal discountPercentage;

    @Column(name = "saleStartDate")
    private LocalDateTime saleStartDate;

    @Column(name = "saleEndDate")
    private LocalDateTime saleEndDate;

    // ============================
    // RATINGS & REVIEWS
    // ============================

    @Column(precision = 3)
    @Builder.Default
    private BigDecimal rating = BigDecimal.ZERO;

    @Column(name = "reviewCount")
    @Builder.Default
    private Integer reviewCount = 0;

    @Column(name = "viewCount")
    @Builder.Default
    private Integer viewCount = 0;

    // ============================
    // INVENTORY MANAGEMENT
    // ============================

    @Column(name = "minimumStockLevel")
    private Integer minimumStockLevel;

    @Column(name = "maximumStockLevel")
    private Integer maximumStockLevel;

    @Column(name = "reorderPoint")
    private Integer reorderPoint;

    @Column(name = "supplierId")
    private Long supplierId;

    // ============================
    // PRODUCT STATUS FLAGS
    // ============================

    @Column(name = "isActive")
    @Builder.Default
    private Boolean isActive = true;

    @Column(name = "isFeatured")
    @Builder.Default
    private Boolean isFeatured = false;

    @Column(name = "isOnSale")
    @Builder.Default
    private Boolean isOnSale = false;

    // ============================
    // SEO AND METADATA
    // ============================

    @Column(length = 200, name = "metaTitle")
    private String metaTitle;

    @Column(length = 500, name = "metaDescription")
    private String metaDescription;

    @Column(length = 500)
    private String tags;

    @Column(length = 1000, name = "saleDescription")
    private String saleDescription;

    // ============================
    // PRODUCT SPECIFICATIONS
    // ============================

    @Column(name = "warrantyMonths")
    private Integer warrantyMonths;

    @Column(name = "estimatedDeliveryDays")
    private Integer estimatedDeliveryDays;

    // ============================
    // AUDIT FIELDS
    // ============================

    @Column(updatable = false, name = "createdAt", nullable = false)
    private LocalDateTime createdAt;

    @Column(name = "updatedAt")
    private LocalDateTime updatedAt;

    // ============================
    // RELATIONSHIPS
    // ============================

    @OneToMany(mappedBy = "product", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    @Builder.Default
    private List<ProductImage> productImages = new ArrayList<>();

    // ============================
    // LIFECYCLE CALLBACKS
    // ============================

    @PrePersist
    protected void onCreate() {
        LocalDateTime now = LocalDateTime.now();
        if (createdAt == null) {
            createdAt = now;
        }
        if (updatedAt == null) {
            updatedAt = now;
        }

        // Set defaults
        if (isActive == null) isActive = true;
        if (isFeatured == null) isFeatured = false;
        if (isOnSale == null) isOnSale = false;
        if (viewCount == null) viewCount = 0;
        if (reviewCount == null) reviewCount = 0;
        if (stockQuantity == null) stockQuantity = 0;
        if (rating == null) rating = BigDecimal.ZERO;
    }

    @PreUpdate
    protected void onUpdate() {
        updatedAt = LocalDateTime.now();
    }

    // ============================
    // PRODUCTSERVICE COMPATIBILITY METHODS
    // ============================

    /**
     * Primary stock getter - ProductService kompatibilitet
     */
    public Integer getStock() {
        return this.stockQuantity;
    }

    /**
     * Primary stock setter - ProductService kompatibilitet
     */
    public void setStock(Integer stock) {
        this.stockQuantity = stock;
    }

    /**
     * Alternative stock getter - fallback compatibility
     */
    public Integer getInventory() {
        return this.stockQuantity;
    }

    /**
     * Alternative stock setter - fallback compatibility
     */
    public void setInventory(Integer inventory) {
        this.stockQuantity = inventory;
    }

    /**
     * Alternative stock getter - fallback compatibility
     */
    public Integer getQuantity() {
        return this.stockQuantity;
    }

    /**
     * Alternative stock setter - fallback compatibility
     */
    public void setQuantity(Integer quantity) {
        this.stockQuantity = quantity;
    }

    // ============================
    // BOOLEAN ALIAS METHODS (för compatibility)
    // ============================

    /**
     * Standard boolean naming convention alias
     */
    public Boolean isActive() {
        return isActive;
    }

    public void setActive(Boolean active) {
        this.isActive = active;
    }

    public Boolean getActive() {
        return isActive;
    }

    /**
     * Featured product aliases
     */
    public Boolean isFeatured() {
        return isFeatured;
    }

    public void setFeatured(Boolean featured) {
        this.isFeatured = featured;
    }

    public Boolean getFeatured() {
        return isFeatured;
    }

    /**
     * On sale aliases
     */
    public Boolean isOnSale() {
        return isOnSale;
    }

    public void setOnSale(Boolean onSale) {
        this.isOnSale = onSale;
    }

    public Boolean getOnSale() {
        return isOnSale;
    }

    // ============================
    // BUSINESS LOGIC METHODS
    // ============================

    /**
     * Kontrollera om produkt är i lager
     */
    public boolean isInStock() {
        return stockQuantity != null && stockQuantity > 0;
    }

    /**
     * Kontrollera om lagersaldo är lågt
     */
    public boolean isLowStock() {
        return minimumStockLevel != null && stockQuantity != null &&
                stockQuantity <= minimumStockLevel;
    }

    /**
     * Kontrollera om produkt behöver beställas
     */
    public boolean needsReorder() {
        return reorderPoint != null && stockQuantity != null &&
                stockQuantity <= reorderPoint;
    }

    /**
     * Hämta effektivt pris (sale price om på rea, annars ordinarie)
     */
    public BigDecimal getEffectivePrice() {
        if (Boolean.TRUE.equals(isOnSale) && salePrice != null) {
            return salePrice;
        }
        return price;
    }

    /**
     * Hämta aktuellt pris (alias för getEffectivePrice)
     */
    public BigDecimal getCurrentPrice() {
        return getEffectivePrice();
    }

    /**
     * Hämta ursprungligt pris för display
     */
    public BigDecimal getOriginalDisplayPrice() {
        return originalPrice != null ? originalPrice : price;
    }

    /**
     * Beräkna besparingar vid rea
     */
    public BigDecimal getSavings() {
        if (Boolean.TRUE.equals(isOnSale) && salePrice != null) {
            BigDecimal originalDisplayPrice = getOriginalDisplayPrice();
            if (originalDisplayPrice.compareTo(salePrice) > 0) {
                return originalDisplayPrice.subtract(salePrice);
            }
        }
        return BigDecimal.ZERO;
    }

    /**
     * Beräkna rabattprocent
     */
    public BigDecimal getCalculatedDiscountPercentage() {
        if (discountPercentage != null) {
            return discountPercentage;
        }

        BigDecimal savings = getSavings();
        BigDecimal originalDisplayPrice = getOriginalDisplayPrice();

        if (savings.compareTo(BigDecimal.ZERO) > 0 &&
                originalDisplayPrice.compareTo(BigDecimal.ZERO) > 0) {
            return savings.divide(originalDisplayPrice, 4, java.math.RoundingMode.HALF_UP)
                    .multiply(new BigDecimal("100"));
        }

        return BigDecimal.ZERO;
    }

    /**
     * Kontrollera om rea är aktiv just nu
     */
    public boolean isSaleActive() {
        if (!Boolean.TRUE.equals(isOnSale)) {
            return false;
        }

        LocalDateTime now = LocalDateTime.now();

        // Kontrollera start datum
        if (saleStartDate != null && now.isBefore(saleStartDate)) {
            return false;
        }

        // Kontrollera slut datum
        if (saleEndDate != null && now.isAfter(saleEndDate)) {
            return false;
        }

        return true;
    }

    /**
     * Öka visningar
     */
    public void incrementViewCount() {
        this.viewCount = (viewCount == null ? 0 : viewCount) + 1;
    }

    /**
     * Lägg till betyg
     */
    public void addRating(BigDecimal newRating) {
        if (newRating == null) return;

        int currentReviews = reviewCount != null ? reviewCount : 0;
        BigDecimal currentRating = rating != null ? rating : BigDecimal.ZERO;

        // Beräkna nytt genomsnittsbetyg
        BigDecimal totalRating = currentRating.multiply(BigDecimal.valueOf(currentReviews));
        totalRating = totalRating.add(newRating);

        this.reviewCount = currentReviews + 1;
        this.rating = totalRating.divide(BigDecimal.valueOf(this.reviewCount), 2,
                java.math.RoundingMode.HALF_UP);
    }

    /**
     * Minska lager
     */
    public boolean decreaseStock(int quantity) {
        if (stockQuantity == null || stockQuantity < quantity) {
            return false;
        }

        stockQuantity -= quantity;
        return true;
    }

    /**
     * Öka lager
     */
    public void increaseStock(int quantity) {
        if (stockQuantity == null) {
            stockQuantity = 0;
        }
        stockQuantity += quantity;
    }

    /**
     * Kontrollera om produkten är tillgänglig för köp
     */
    public boolean isAvailableForPurchase() {
        return Boolean.TRUE.equals(isActive) && isInStock();
    }

    /**
     * Kontrollera om produkten är synlig för kunder
     */
    public boolean isVisible() {
        return Boolean.TRUE.equals(isActive);
    }

    // ============================
    // DISPLAY METHODS
    // ============================

    /**
     * Hämta formatted pris för display
     */
    public String getFormattedPrice() {
        BigDecimal effectivePrice = getEffectivePrice();
        return String.format("%.2f SEK", effectivePrice);
    }

    /**
     * Hämta kort beskrivning (första 100 tecken)
     */
    public String getShortDescription() {
        if (description == null || description.trim().isEmpty()) {
            return "";
        }

        String clean = description.trim();
        if (clean.length() <= 100) {
            return clean;
        }

        return clean.substring(0, 97) + "...";
    }

    /**
     * Hämta första produktbild URL
     */
    public String getPrimaryImageUrl() {
        if (imageUrl != null && !imageUrl.trim().isEmpty()) {
            return imageUrl;
        }

        if (productImages != null && !productImages.isEmpty()) {
            ProductImage firstImage = productImages.get(0);
            return firstImage.getImageUrl();
        }

        return "/images/no-image.jpg"; // Default fallback
    }

    // ============================
    // SEARCH & SEO METHODS
    // ============================

    /**
     * Hämta searchable text för indexing
     */
    public String getSearchableText() {
        StringBuilder sb = new StringBuilder();

        if (name != null) sb.append(name).append(" ");
        if (description != null) sb.append(description).append(" ");
        if (brand != null) sb.append(brand).append(" ");
        if (model != null) sb.append(model).append(" ");
        if (color != null) sb.append(color).append(" ");
        if (category != null) sb.append(category).append(" ");
        if (tags != null) sb.append(tags).append(" ");

        return sb.toString().toLowerCase().trim();
    }

    /**
     * Hämta meta title för SEO (fallback till product name)
     */
    public String getEffectiveMetaTitle() {
        return metaTitle != null && !metaTitle.trim().isEmpty() ? metaTitle : name;
    }

    /**
     * Hämta meta description för SEO (fallback till short description)
     */
    public String getEffectiveMetaDescription() {
        if (metaDescription != null && !metaDescription.trim().isEmpty()) {
            return metaDescription;
        }
        return getShortDescription();
    }

    // ============================
    // VALIDATION METHODS
    // ============================

    /**
     * Validera att produkten har all nödvändig information
     */
    public boolean isValid() {
        return name != null && !name.trim().isEmpty() &&
                price != null && price.compareTo(BigDecimal.ZERO) >= 0 &&
                category != null && !category.trim().isEmpty() &&
                stockQuantity != null && stockQuantity >= 0;
    }

    /**
     * Hämta lista över validation errors
     */
    public List<String> getValidationErrors() {
        List<String> errors = new ArrayList<>();

        if (name == null || name.trim().isEmpty()) {
            errors.add("Product name is required");
        }

        if (price == null) {
            errors.add("Price is required");
        } else if (price.compareTo(BigDecimal.ZERO) < 0) {
            errors.add("Price cannot be negative");
        }

        if (category == null || category.trim().isEmpty()) {
            errors.add("Category is required");
        }

        if (stockQuantity == null) {
            errors.add("Stock quantity is required");
        } else if (stockQuantity < 0) {
            errors.add("Stock quantity cannot be negative");
        }

        return errors;
    }

    // ============================
    // CONSTRUCTORS (additional)
    // ============================

    /**
     * Convenience constructor för basic product creation
     */
    public Product(String name, String description, BigDecimal price, String category, Integer stockQuantity) {
        this();
        this.name = name;
        this.description = description;
        this.price = price;
        this.category = category;
        this.stockQuantity = stockQuantity;
    }

    /**
     * Constructor för quick product setup
     */
    public Product(String name, BigDecimal price, String category) {
        this(name, null, price, category, 0);
    }
}