package dev.lions.unionflow.server.entity;

import jakarta.persistence.*;
import jakarta.validation.constraints.*;
import java.math.BigDecimal;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;

/**
 * Entité Ligne Budgétaire
 *
 * Représente une ligne dans un budget (catégorie de dépense/recette).
 *
 * @author UnionFlow Team
 * @version 1.0
 * @since 2026-03-13
 */
@Entity
@Table(name = "budget_lines", indexes = {
    @Index(name = "idx_budget_line_budget", columnList = "budget_id"),
    @Index(name = "idx_budget_line_category", columnList = "category")
})
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@EqualsAndHashCode(callSuper = true)
public class BudgetLine extends BaseEntity {

    /** Budget parent */
    @NotNull
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "budget_id", nullable = false)
    private Budget budget;

    /** Catégorie (CONTRIBUTIONS, SAVINGS, SOLIDARITY, EVENTS, OPERATIONAL, INVESTMENTS, OTHER) */
    @NotBlank
    @Pattern(regexp = "^(CONTRIBUTIONS|SAVINGS|SOLIDARITY|EVENTS|OPERATIONAL|INVESTMENTS|OTHER)$")
    @Column(name = "category", nullable = false, length = 20)
    private String category;

    /** Nom de la ligne */
    @NotBlank
    @Size(max = 200)
    @Column(name = "name", nullable = false, length = 200)
    private String name;

    /** Description optionnelle */
    @Size(max = 500)
    @Column(name = "description", length = 500)
    private String description;

    /** Montant prévu */
    @NotNull
    @DecimalMin(value = "0.0")
    @Digits(integer = 14, fraction = 2)
    @Column(name = "amount_planned", nullable = false, precision = 16, scale = 2)
    private BigDecimal amountPlanned;

    /** Montant réalisé */
    @DecimalMin(value = "0.0")
    @Digits(integer = 14, fraction = 2)
    @Builder.Default
    @Column(name = "amount_realized", nullable = false, precision = 16, scale = 2)
    private BigDecimal amountRealized = BigDecimal.ZERO;

    /** Notes additionnelles */
    @Size(max = 1000)
    @Column(name = "notes", length = 1000)
    private String notes;

    @PrePersist
    protected void onCreate() {
        super.onCreate();
        if (amountRealized == null) {
            amountRealized = BigDecimal.ZERO;
        }
    }

    /** Méthode métier pour calculer le taux de réalisation (%) */
    public double getRealizationRate() {
        if (amountPlanned.compareTo(BigDecimal.ZERO) == 0) {
            return 0.0;
        }
        return amountRealized.divide(amountPlanned, 4, java.math.RoundingMode.HALF_UP)
            .multiply(new BigDecimal("100"))
            .doubleValue();
    }

    /** Méthode métier pour calculer l'écart */
    public BigDecimal getVariance() {
        return amountRealized.subtract(amountPlanned);
    }

    /** Méthode métier pour vérifier si la ligne est dépassée */
    public boolean isOverBudget() {
        return amountRealized.compareTo(amountPlanned) > 0;
    }
}
