package dev.lions.unionflow.server.api.dto.paiement;

import com.fasterxml.jackson.annotation.JsonFormat;
import dev.lions.unionflow.server.api.dto.base.BaseDTO;
import jakarta.validation.constraints.DecimalMin;
import jakarta.validation.constraints.Digits;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Pattern;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import lombok.Getter;
import lombok.Setter;

/**
 * DTO pour la consultation du solde Wave Money (Balance API) Représente le solde d'un wallet Wave
 * Business
 *
 * <p>Basé sur l'API officielle Wave : https://docs.wave.com/business#balance-api
 *
 * @author UnionFlow Team
 * @version 1.0
 * @since 2025-01-10
 */
@Getter
@Setter
public class WaveBalanceDTO extends BaseDTO {

  private static final long serialVersionUID = 1L;

  /** Solde disponible */
  @NotNull(message = "Le solde disponible est obligatoire")
  @DecimalMin(value = "0.0", message = "Le solde doit être positif ou nul")
  @Digits(
      integer = 12,
      fraction = 2,
      message = "Le solde ne peut avoir plus de 12 chiffres entiers et 2 décimales")
  private BigDecimal soldeDisponible;

  /** Solde en attente (transactions en cours) */
  @DecimalMin(value = "0.0", message = "Le solde en attente doit être positif ou nul")
  @Digits(
      integer = 12,
      fraction = 2,
      message = "Le solde ne peut avoir plus de 12 chiffres entiers et 2 décimales")
  private BigDecimal soldeEnAttente;

  /** Solde total (disponible + en attente) */
  @DecimalMin(value = "0.0", message = "Le solde total doit être positif ou nul")
  @Digits(
      integer = 12,
      fraction = 2,
      message = "Le solde ne peut avoir plus de 12 chiffres entiers et 2 décimales")
  private BigDecimal soldeTotal;

  /** Devise du wallet */
  @NotBlank(message = "La devise est obligatoire")
  @Pattern(regexp = "^[A-Z]{3}$", message = "La devise doit être un code ISO à 3 lettres")
  private String devise = "XOF";

  /** Numéro du wallet Wave */
  @NotBlank(message = "Le numéro de wallet est obligatoire")
  private String numeroWallet;

  /** Nom du business associé au wallet */
  private String nomBusiness;

  /** Date de dernière mise à jour du solde */
  @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
  private LocalDateTime dateDerniereMiseAJour;

  /** Date de dernière synchronisation avec Wave */
  @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
  private LocalDateTime dateDerniereSynchronisation;

  /** Statut du wallet */
  @Pattern(
      regexp = "^(ACTIVE|INACTIVE|SUSPENDED|BLOCKED)$",
      message = "Le statut doit être ACTIVE, INACTIVE, SUSPENDED ou BLOCKED")
  private String statutWallet;

  /** Limite de transaction quotidienne */
  @DecimalMin(value = "0.0", message = "La limite doit être positive ou nulle")
  @Digits(
      integer = 12,
      fraction = 2,
      message = "La limite ne peut avoir plus de 12 chiffres entiers et 2 décimales")
  private BigDecimal limiteQuotidienne;

  /** Montant déjà utilisé aujourd'hui */
  @DecimalMin(value = "0.0", message = "Le montant utilisé doit être positif ou nul")
  @Digits(
      integer = 12,
      fraction = 2,
      message = "Le montant ne peut avoir plus de 12 chiffres entiers et 2 décimales")
  private BigDecimal montantUtiliseAujourdhui;

  /** Limite mensuelle */
  @DecimalMin(value = "0.0", message = "La limite doit être positive ou nulle")
  @Digits(
      integer = 12,
      fraction = 2,
      message = "La limite ne peut avoir plus de 12 chiffres entiers et 2 décimales")
  private BigDecimal limiteMensuelle;

  /** Montant utilisé ce mois */
  @DecimalMin(value = "0.0", message = "Le montant utilisé doit être positif ou nul")
  @Digits(
      integer = 12,
      fraction = 2,
      message = "Le montant ne peut avoir plus de 12 chiffres entiers et 2 décimales")
  private BigDecimal montantUtiliseCeMois;

  /** Nombre de transactions aujourd'hui */
  private Integer nombreTransactionsAujourdhui;

  /** Nombre de transactions ce mois */
  private Integer nombreTransactionsCeMois;

  /** Dernière erreur de synchronisation */
  private String derniereErreur;

  /** Code de la dernière erreur */
  private String codeDerniereErreur;

  // Constructeurs
  public WaveBalanceDTO() {
    super();
    this.devise = "XOF";
    this.statutWallet = "ACTIVE";
    this.soldeEnAttente = BigDecimal.ZERO;
    this.montantUtiliseAujourdhui = BigDecimal.ZERO;
    this.montantUtiliseCeMois = BigDecimal.ZERO;
    this.nombreTransactionsAujourdhui = 0;
    this.nombreTransactionsCeMois = 0;
  }

  public WaveBalanceDTO(String numeroWallet, BigDecimal soldeDisponible) {
    this();
    this.numeroWallet = numeroWallet;
    this.soldeDisponible = soldeDisponible;
    this.soldeTotal = soldeDisponible;
  }

  // Getters et Setters
  public BigDecimal getSoldeDisponible() {
    return soldeDisponible;
  }

  public void setSoldeDisponible(BigDecimal soldeDisponible) {
    this.soldeDisponible = soldeDisponible;
    calculerSoldeTotal();
  }

  public BigDecimal getSoldeEnAttente() {
    return soldeEnAttente;
  }

  public void setSoldeEnAttente(BigDecimal soldeEnAttente) {
    this.soldeEnAttente = soldeEnAttente;
    calculerSoldeTotal();
  }

  public BigDecimal getSoldeTotal() {
    return soldeTotal;
  }

  public void setSoldeTotal(BigDecimal soldeTotal) {
    this.soldeTotal = soldeTotal;
  }

  public String getDevise() {
    return devise;
  }

  public void setDevise(String devise) {
    this.devise = devise;
  }

  public String getNumeroWallet() {
    return numeroWallet;
  }

  public void setNumeroWallet(String numeroWallet) {
    this.numeroWallet = numeroWallet;
  }

  public String getNomBusiness() {
    return nomBusiness;
  }

  public void setNomBusiness(String nomBusiness) {
    this.nomBusiness = nomBusiness;
  }

  public LocalDateTime getDateDerniereMiseAJour() {
    return dateDerniereMiseAJour;
  }

  public void setDateDerniereMiseAJour(LocalDateTime dateDerniereMiseAJour) {
    this.dateDerniereMiseAJour = dateDerniereMiseAJour;
  }

  public LocalDateTime getDateDerniereSynchronisation() {
    return dateDerniereSynchronisation;
  }

  public void setDateDerniereSynchronisation(LocalDateTime dateDerniereSynchronisation) {
    this.dateDerniereSynchronisation = dateDerniereSynchronisation;
  }

  public String getStatutWallet() {
    return statutWallet;
  }

  public void setStatutWallet(String statutWallet) {
    this.statutWallet = statutWallet;
  }

  public BigDecimal getLimiteQuotidienne() {
    return limiteQuotidienne;
  }

  public void setLimiteQuotidienne(BigDecimal limiteQuotidienne) {
    this.limiteQuotidienne = limiteQuotidienne;
  }

  public BigDecimal getMontantUtiliseAujourdhui() {
    return montantUtiliseAujourdhui;
  }

  public void setMontantUtiliseAujourdhui(BigDecimal montantUtiliseAujourdhui) {
    this.montantUtiliseAujourdhui = montantUtiliseAujourdhui;
  }

  public BigDecimal getLimiteMensuelle() {
    return limiteMensuelle;
  }

  public void setLimiteMensuelle(BigDecimal limiteMensuelle) {
    this.limiteMensuelle = limiteMensuelle;
  }

  public BigDecimal getMontantUtiliseCeMois() {
    return montantUtiliseCeMois;
  }

  public void setMontantUtiliseCeMois(BigDecimal montantUtiliseCeMois) {
    this.montantUtiliseCeMois = montantUtiliseCeMois;
  }

  public Integer getNombreTransactionsAujourdhui() {
    return nombreTransactionsAujourdhui;
  }

  public void setNombreTransactionsAujourdhui(Integer nombreTransactionsAujourdhui) {
    this.nombreTransactionsAujourdhui = nombreTransactionsAujourdhui;
  }

  public Integer getNombreTransactionsCeMois() {
    return nombreTransactionsCeMois;
  }

  public void setNombreTransactionsCeMois(Integer nombreTransactionsCeMois) {
    this.nombreTransactionsCeMois = nombreTransactionsCeMois;
  }

  public String getDerniereErreur() {
    return derniereErreur;
  }

  public void setDerniereErreur(String derniereErreur) {
    this.derniereErreur = derniereErreur;
  }

  public String getCodeDerniereErreur() {
    return codeDerniereErreur;
  }

  public void setCodeDerniereErreur(String codeDerniereErreur) {
    this.codeDerniereErreur = codeDerniereErreur;
  }

  // Méthodes utilitaires

  /** Calcule le solde total */
  private void calculerSoldeTotal() {
    if (soldeDisponible != null && soldeEnAttente != null) {
      this.soldeTotal = soldeDisponible.add(soldeEnAttente);
    }
  }

  /**
   * Vérifie si le wallet est actif
   *
   * @return true si le wallet est actif
   */
  public boolean isWalletActif() {
    return "ACTIVE".equals(statutWallet);
  }

  /**
   * Vérifie si le solde est suffisant pour un montant donné
   *
   * @param montant Le montant à vérifier
   * @return true si le solde est suffisant
   */
  public boolean isSoldeSuffisant(BigDecimal montant) {
    return soldeDisponible != null && soldeDisponible.compareTo(montant) >= 0;
  }

  /**
   * Calcule le solde disponible restant pour aujourd'hui
   *
   * @return Le montant encore disponible aujourd'hui
   */
  public BigDecimal getSoldeDisponibleAujourdhui() {
    if (soldeDisponible == null || limiteQuotidienne == null || montantUtiliseAujourdhui == null) {
      return soldeDisponible;
    }

    BigDecimal limiteRestante = limiteQuotidienne.subtract(montantUtiliseAujourdhui);
    return soldeDisponible.min(limiteRestante);
  }

  /**
   * Met à jour les statistiques après une transaction
   *
   * @param montant Le montant de la transaction
   */
  public void mettreAJourApresTransaction(BigDecimal montant) {
    if (montantUtiliseAujourdhui == null) montantUtiliseAujourdhui = BigDecimal.ZERO;
    if (montantUtiliseCeMois == null) montantUtiliseCeMois = BigDecimal.ZERO;
    if (nombreTransactionsAujourdhui == null) nombreTransactionsAujourdhui = 0;
    if (nombreTransactionsCeMois == null) nombreTransactionsCeMois = 0;

    this.montantUtiliseAujourdhui = montantUtiliseAujourdhui.add(montant);
    this.montantUtiliseCeMois = montantUtiliseCeMois.add(montant);
    this.nombreTransactionsAujourdhui++;
    this.nombreTransactionsCeMois++;
    this.dateDerniereMiseAJour = LocalDateTime.now();
  }

  @Override
  public String toString() {
    return "WaveBalanceDTO{"
        + "numeroWallet='"
        + numeroWallet
        + '\''
        + ", soldeDisponible="
        + soldeDisponible
        + ", soldeTotal="
        + soldeTotal
        + ", devise='"
        + devise
        + '\''
        + ", statutWallet='"
        + statutWallet
        + '\''
        + "} "
        + super.toString();
  }
}
