package dev.lions.unionflow.server.entity;

import dev.lions.unionflow.server.api.enums.paiement.StatutIntentionPaiement;
import dev.lions.unionflow.server.api.enums.paiement.TypeObjetIntentionPaiement;
import jakarta.persistence.*;
import jakarta.validation.constraints.*;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import lombok.*;

/**
 * Hub centralisé pour tout paiement Wave initié depuis UnionFlow.
 *
 * <p>Flux :
 * <ol>
 *   <li>UnionFlow crée une {@code IntentionPaiement} avec les objets cibles (cotisations, etc.)</li>
 *   <li>UnionFlow appelle l'API Wave → récupère {@code waveCheckoutSessionId}</li>
 *   <li>Le membre confirme dans l'app Wave</li>
 *   <li>Wave envoie un webhook → UnionFlow réconcilie via {@code waveCheckoutSessionId}</li>
 *   <li>UnionFlow valide automatiquement les objets listés dans {@code objetsCibles}</li>
 * </ol>
 *
 * <p>Table : {@code intentions_paiement}
 */
@Entity
@Table(
    name = "intentions_paiement",
    indexes = {
      @Index(name = "idx_intention_utilisateur",   columnList = "utilisateur_id"),
      @Index(name = "idx_intention_statut",        columnList = "statut"),
      @Index(name = "idx_intention_wave_session",  columnList = "wave_checkout_session_id", unique = true),
      @Index(name = "idx_intention_expiration",    columnList = "date_expiration")
    })
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@EqualsAndHashCode(callSuper = true)
public class IntentionPaiement extends BaseEntity {

  @NotNull
  @ManyToOne(fetch = FetchType.LAZY)
  @JoinColumn(name = "utilisateur_id", nullable = false)
  private Membre utilisateur;

  /** NULL pour les abonnements UnionFlow SA (payés par l'organisation directement) */
  @ManyToOne(fetch = FetchType.LAZY)
  @JoinColumn(name = "organisation_id")
  private Organisation organisation;

  @NotNull
  @DecimalMin("0.01")
  @Digits(integer = 12, fraction = 2)
  @Column(name = "montant_total", nullable = false, precision = 14, scale = 2)
  private BigDecimal montantTotal;

  @NotBlank
  @Pattern(regexp = "^[A-Z]{3}$")
  @Builder.Default
  @Column(name = "code_devise", nullable = false, length = 3)
  private String codeDevise = "XOF";

  @Enumerated(EnumType.STRING)
  @NotNull
  @Column(name = "type_objet", nullable = false, length = 30)
  private TypeObjetIntentionPaiement typeObjet;

  @Enumerated(EnumType.STRING)
  @Builder.Default
  @Column(name = "statut", nullable = false, length = 20)
  private StatutIntentionPaiement statut = StatutIntentionPaiement.INITIEE;

  /** ID de session Wave — clé de réconciliation sur webhook */
  @Column(name = "wave_checkout_session_id", unique = true, length = 255)
  private String waveCheckoutSessionId;

  /** URL de paiement Wave à rediriger l'utilisateur */
  @Column(name = "wave_launch_url", length = 1000)
  private String waveLaunchUrl;

  /** ID transaction Wave reçu via webhook */
  @Column(name = "wave_transaction_id", length = 100)
  private String waveTransactionId;

  /**
   * JSON : liste des objets couverts par ce paiement.
   * Exemple : [{\"type\":\"COTISATION\",\"id\":\"uuid\",\"montant\":5000}, ...]
   */
  @Column(name = "objets_cibles", columnDefinition = "TEXT")
  private String objetsCibles;

  @Column(name = "date_expiration")
  private LocalDateTime dateExpiration;

  @Column(name = "date_completion")
  private LocalDateTime dateCompletion;

  // ── Méthodes métier ────────────────────────────────────────────────────────

  public boolean isActive() {
    return StatutIntentionPaiement.INITIEE.equals(statut)
        || StatutIntentionPaiement.EN_COURS.equals(statut);
  }

  public boolean isExpiree() {
    return dateExpiration != null && LocalDateTime.now().isAfter(dateExpiration);
  }

  public boolean isCompletee() {
    return StatutIntentionPaiement.COMPLETEE.equals(statut);
  }

  @PrePersist
  protected void onCreate() {
    super.onCreate();
    if (statut == null)    statut    = StatutIntentionPaiement.INITIEE;
    if (codeDevise == null) codeDevise = "XOF";
    if (dateExpiration == null) {
      dateExpiration = LocalDateTime.now().plusMinutes(30);
    }
  }
}
