package dev.lions.unionflow.server.entity;

import com.fasterxml.jackson.annotation.JsonIgnore;
import dev.lions.unionflow.server.api.enums.membre.StatutMembre;
import jakarta.persistence.*;
import jakarta.validation.constraints.NotNull;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import lombok.*;

/**
 * Lien entre un utilisateur et une organisation.
 *
 * <p>Un utilisateur peut adhérer à plusieurs organisations simultanément.
 * Chaque adhésion a son propre statut, date et unité d'affectation.
 *
 * <p>Table : {@code membres_organisations}
 */
@Entity
@Table(
    name = "membres_organisations",
    indexes = {
      @Index(name = "idx_mo_utilisateur",  columnList = "utilisateur_id"),
      @Index(name = "idx_mo_organisation", columnList = "organisation_id"),
      @Index(name = "idx_mo_statut",       columnList = "statut_membre"),
      @Index(name = "idx_mo_unite",        columnList = "unite_id")
    },
    uniqueConstraints = {
      @UniqueConstraint(
          name = "uk_mo_utilisateur_organisation",
          columnNames = {"utilisateur_id", "organisation_id"})
    })
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@EqualsAndHashCode(callSuper = true)
public class MembreOrganisation extends BaseEntity {

  /** L'utilisateur (identité globale) */
  @NotNull
  @ManyToOne(fetch = FetchType.LAZY)
  @JoinColumn(name = "utilisateur_id", nullable = false)
  private Membre membre;

  /** L'organisation racine à laquelle appartient ce membre */
  @NotNull
  @ManyToOne(fetch = FetchType.LAZY)
  @JoinColumn(name = "organisation_id", nullable = false)
  private Organisation organisation;

  /**
   * Unité d'affectation (agence/bureau).
   * NULL = affecté au siège.
   */
  @ManyToOne(fetch = FetchType.LAZY)
  @JoinColumn(name = "unite_id")
  private Organisation unite;

  @Enumerated(EnumType.STRING)
  @Builder.Default
  @Column(name = "statut_membre", nullable = false, length = 30)
  private StatutMembre statutMembre = StatutMembre.EN_ATTENTE_VALIDATION;

  @Column(name = "date_adhesion")
  private LocalDate dateAdhesion;

  @Column(name = "date_changement_statut")
  private LocalDate dateChangementStatut;

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

  /** Utilisateur qui a approuvé ou traité ce changement de statut */
  @ManyToOne(fetch = FetchType.LAZY)
  @JoinColumn(name = "approuve_par_id")
  private Membre approuvePar;

  // ── Champs d'invitation (StatutMembre.INVITE) ──────────────────────────────

  /** Date à laquelle l'invitation a été envoyée. */
  @Column(name = "date_invitation")
  private LocalDateTime dateInvitation;

  /** Date d'expiration de l'invitation (null = pas d'expiration). */
  @Column(name = "date_expiration_invitation")
  private LocalDateTime dateExpirationInvitation;

  /** Token opaque utilisé dans le lien d'invitation envoyé par email. */
  @Column(name = "token_invitation", length = 64)
  private String tokenInvitation;

  /** ID de l'administrateur qui a envoyé l'invitation. */
  @Column(name = "invite_par")
  private UUID invitePar;

  /** Motif d'archivage (pour StatutMembre.ARCHIVE). */
  @Column(name = "motif_archivage", length = 500)
  private String motifArchivage;

  // ── Rôle fonctionnel dans l'organisation ─────────────────────────────────

  /** Rôle de ce membre dans l'organisation (ex: PRESIDENT, TRESORIER...). */
  @Column(name = "role_org", length = 50)
  private String roleOrg;

  // ── Relations ─────────────────────────────────────────────────────────────

  /** Rôles de ce membre dans cette organisation */
  @JsonIgnore
  @OneToMany(mappedBy = "membreOrganisation", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
  @Builder.Default
  private List<MembreRole> roles = new ArrayList<>();

  /** Ayants droit (mutuelles de santé uniquement) */
  @JsonIgnore
  @OneToMany(mappedBy = "membreOrganisation", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
  @Builder.Default
  private List<AyantDroit> ayantsDroit = new ArrayList<>();

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

  public boolean isActif() {
    return StatutMembre.ACTIF.equals(statutMembre) && Boolean.TRUE.equals(getActif());
  }

  public boolean peutDemanderAide() {
    return StatutMembre.ACTIF.equals(statutMembre);
  }

  @PrePersist
  protected void onCreate() {
    super.onCreate();
    if (statutMembre == null) {
      statutMembre = StatutMembre.EN_ATTENTE_VALIDATION;
    }
  }
}
