package dev.lions.unionflow.client.dto;

import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.UUID;

/**
 * DTO pour la gestion des adhésions côté client
 * Correspond au AdhesionDTO du backend avec méthodes utilitaires pour l'affichage
 * 
 * @author UnionFlow Team
 * @version 1.0
 */
public class AdhesionDTO implements Serializable {
    
    private static final long serialVersionUID = 1L;
    
    private UUID id;
    private String numeroReference;
    private UUID membreId;
    private String numeroMembre;
    private String nomMembre;
    private String emailMembre;
    private UUID organisationId;
    private String nomOrganisation;
    private LocalDate dateDemande;
    private BigDecimal fraisAdhesion;
    private BigDecimal montantPaye;
    private String codeDevise;
    private String statut;
    private LocalDate dateApprobation;
    private LocalDateTime datePaiement;
    private String methodePaiement;
    private String referencePaiement;
    private String motifRejet;
    private String observations;
    private String approuvePar;
    private LocalDate dateValidation;
    private LocalDateTime dateCreation;
    private LocalDateTime dateModification;
    private Boolean actif;
    
    // Getters et Setters
    public UUID getId() { return id; }
    public void setId(UUID id) { this.id = id; }
    
    public String getNumeroReference() { return numeroReference; }
    public void setNumeroReference(String numeroReference) { this.numeroReference = numeroReference; }
    
    public UUID getMembreId() { return membreId; }
    public void setMembreId(UUID membreId) { this.membreId = membreId; }
    
    public String getNumeroMembre() { return numeroMembre; }
    public void setNumeroMembre(String numeroMembre) { this.numeroMembre = numeroMembre; }
    
    public String getNomMembre() { return nomMembre; }
    public void setNomMembre(String nomMembre) { this.nomMembre = nomMembre; }
    
    public String getEmailMembre() { return emailMembre; }
    public void setEmailMembre(String emailMembre) { this.emailMembre = emailMembre; }
    
    public UUID getOrganisationId() { return organisationId; }
    public void setOrganisationId(UUID organisationId) { this.organisationId = organisationId; }
    
    public String getNomOrganisation() { return nomOrganisation; }
    public void setNomOrganisation(String nomOrganisation) { this.nomOrganisation = nomOrganisation; }
    
    public LocalDate getDateDemande() { return dateDemande; }
    public void setDateDemande(LocalDate dateDemande) { this.dateDemande = dateDemande; }
    
    public BigDecimal getFraisAdhesion() { return fraisAdhesion; }
    public void setFraisAdhesion(BigDecimal fraisAdhesion) { this.fraisAdhesion = fraisAdhesion; }
    
    public BigDecimal getMontantPaye() { return montantPaye != null ? montantPaye : BigDecimal.ZERO; }
    public void setMontantPaye(BigDecimal montantPaye) { this.montantPaye = montantPaye; }
    
    public String getCodeDevise() { return codeDevise; }
    public void setCodeDevise(String codeDevise) { this.codeDevise = codeDevise; }
    
    public String getStatut() { return statut; }
    public void setStatut(String statut) { this.statut = statut; }
    
    public LocalDate getDateApprobation() { return dateApprobation; }
    public void setDateApprobation(LocalDate dateApprobation) { this.dateApprobation = dateApprobation; }
    
    public LocalDateTime getDatePaiement() { return datePaiement; }
    public void setDatePaiement(LocalDateTime datePaiement) { this.datePaiement = datePaiement; }
    
    public String getMethodePaiement() { return methodePaiement; }
    public void setMethodePaiement(String methodePaiement) { this.methodePaiement = methodePaiement; }
    
    public String getReferencePaiement() { return referencePaiement; }
    public void setReferencePaiement(String referencePaiement) { this.referencePaiement = referencePaiement; }
    
    public String getMotifRejet() { return motifRejet; }
    public void setMotifRejet(String motifRejet) { this.motifRejet = motifRejet; }
    
    public String getObservations() { return observations; }
    public void setObservations(String observations) { this.observations = observations; }
    
    public String getApprouvePar() { return approuvePar; }
    public void setApprouvePar(String approuvePar) { this.approuvePar = approuvePar; }
    
    public LocalDate getDateValidation() { return dateValidation; }
    public void setDateValidation(LocalDate dateValidation) { this.dateValidation = dateValidation; }
    
    public LocalDateTime getDateCreation() { return dateCreation; }
    public void setDateCreation(LocalDateTime dateCreation) { this.dateCreation = dateCreation; }
    
    public LocalDateTime getDateModification() { return dateModification; }
    public void setDateModification(LocalDateTime dateModification) { this.dateModification = dateModification; }
    
    public Boolean getActif() { return actif; }
    public void setActif(Boolean actif) { this.actif = actif; }
    
    // Méthodes utilitaires pour l'affichage (alignées avec le backend)
    
    /**
     * Vérifie si l'adhésion est payée intégralement
     */
    public boolean isPayeeIntegralement() {
        return montantPaye != null && fraisAdhesion != null && montantPaye.compareTo(fraisAdhesion) >= 0;
    }
    
    /**
     * Vérifie si l'adhésion est en attente de paiement
     */
    public boolean isEnAttentePaiement() {
        return "APPROUVEE".equals(statut) && !isPayeeIntegralement();
    }
    
    /**
     * Calcule le montant restant à payer
     */
    public BigDecimal getMontantRestant() {
        if (fraisAdhesion == null) return BigDecimal.ZERO;
        if (montantPaye == null) return fraisAdhesion;
        BigDecimal restant = fraisAdhesion.subtract(montantPaye);
        return restant.compareTo(BigDecimal.ZERO) > 0 ? restant : BigDecimal.ZERO;
    }
    
    /**
     * Calcule le pourcentage de paiement
     */
    public int getPourcentagePaiement() {
        if (fraisAdhesion == null || fraisAdhesion.compareTo(BigDecimal.ZERO) == 0) return 0;
        if (montantPaye == null) return 0;
        return montantPaye.multiply(BigDecimal.valueOf(100))
                .divide(fraisAdhesion, 0, java.math.RoundingMode.HALF_UP)
                .intValue();
    }
    
    /**
     * Calcule le nombre de jours depuis la demande
     */
    public long getJoursDepuisDemande() {
        if (dateDemande == null) return 0;
        return ChronoUnit.DAYS.between(dateDemande, LocalDate.now());
    }
    
    /**
     * Retourne le libellé du statut
     */
    public String getStatutLibelle() {
        if (statut == null) return "Non défini";
        return switch (statut) {
            case "EN_ATTENTE" -> "En attente";
            case "APPROUVEE" -> "Approuvée";
            case "REJETEE" -> "Rejetée";
            case "ANNULEE" -> "Annulée";
            case "EN_PAIEMENT" -> "En paiement";
            case "PAYEE" -> "Payée";
            default -> statut;
        };
    }
    
    /**
     * Retourne la sévérité du statut pour PrimeFaces
     */
    public String getStatutSeverity() {
        if (statut == null) return "secondary";
        return switch (statut) {
            case "APPROUVEE", "PAYEE" -> "success";
            case "EN_ATTENTE", "EN_PAIEMENT" -> "warning";
            case "REJETEE" -> "danger";
            case "ANNULEE" -> "secondary";
            default -> "secondary";
        };
    }
    
    /**
     * Retourne l'icône du statut pour PrimeFaces
     */
    public String getStatutIcon() {
        if (statut == null) return "pi-circle";
        return switch (statut) {
            case "APPROUVEE", "PAYEE" -> "pi-check";
            case "EN_ATTENTE" -> "pi-clock";
            case "EN_PAIEMENT" -> "pi-credit-card";
            case "REJETEE" -> "pi-times";
            case "ANNULEE" -> "pi-ban";
            default -> "pi-circle";
        };
    }
    
    /**
     * Retourne le libellé de la méthode de paiement
     */
    public String getMethodePaiementLibelle() {
        if (methodePaiement == null) return "Non défini";
        return switch (methodePaiement) {
            case "ESPECES" -> "Espèces";
            case "VIREMENT" -> "Virement bancaire";
            case "CHEQUE" -> "Chèque";
            case "WAVE_MONEY" -> "Wave Money";
            case "ORANGE_MONEY" -> "Orange Money";
            case "FREE_MONEY" -> "Free Money";
            case "CARTE_BANCAIRE" -> "Carte bancaire";
            default -> methodePaiement;
        };
    }
    
    /**
     * Formate la date de demande
     */
    public String getDateDemandeFormatee() {
        if (dateDemande == null) return "";
        return dateDemande.format(DateTimeFormatter.ofPattern("dd/MM/yyyy"));
    }
    
    /**
     * Formate la date d'approbation
     */
    public String getDateApprobationFormatee() {
        if (dateApprobation == null) return "";
        return dateApprobation.format(DateTimeFormatter.ofPattern("dd/MM/yyyy"));
    }
    
    /**
     * Formate la date de paiement
     */
    public String getDatePaiementFormatee() {
        if (datePaiement == null) return "";
        return datePaiement.format(DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm"));
    }
    
    /**
     * Formate les frais d'adhésion
     */
    public String getFraisAdhesionFormatte() {
        if (fraisAdhesion == null) return "0 FCFA";
        return String.format("%,.0f FCFA", fraisAdhesion.doubleValue());
    }
    
    /**
     * Formate le montant payé
     */
    public String getMontantPayeFormatte() {
        if (montantPaye == null) return "0 FCFA";
        return String.format("%,.0f FCFA", montantPaye.doubleValue());
    }
    
    /**
     * Formate le montant restant
     */
    public String getMontantRestantFormatte() {
        return String.format("%,.0f FCFA", getMontantRestant().doubleValue());
    }
}

