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

import com.fasterxml.jackson.annotation.JsonFormat;
import dev.lions.unionflow.server.api.dto.base.BaseDTO;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Past;
import jakarta.validation.constraints.Pattern;
import jakarta.validation.constraints.Size;
import java.time.LocalDate;
import lombok.Getter;
import lombok.Setter;

/**
 * DTO pour la gestion des membres dans l'API UnionFlow Contient toutes les informations relatives à
 * un membre d'une organisation
 *
 * @author UnionFlow Team
 * @version 1.0
 * @since 2025-01-10
 */
@Getter
@Setter
public class MembreDTO extends BaseDTO {

  private static final long serialVersionUID = 1L;

  /** Numéro unique du membre (format: UF-YYYY-XXXXXXXX) */
  @NotBlank(message = "Le numéro de membre est obligatoire")
  @Pattern(
      regexp = "^UF-\\d{4}-[A-Z0-9]{8}$",
      message = "Format de numéro de membre invalide (UF-YYYY-XXXXXXXX)")
  private String numeroMembre;

  /** Nom de famille du membre */
  @NotBlank(message = "Le nom est obligatoire")
  @Size(min = 2, max = 50, message = "Le nom doit contenir entre 2 et 50 caractères")
  @Pattern(
      regexp = "^[a-zA-ZÀ-ÿ\\s\\-']+$",
      message = "Le nom ne peut contenir que des lettres, espaces, tirets et apostrophes")
  private String nom;

  /** Prénom du membre */
  @NotBlank(message = "Le prénom est obligatoire")
  @Size(min = 2, max = 50, message = "Le prénom doit contenir entre 2 et 50 caractères")
  @Pattern(
      regexp = "^[a-zA-ZÀ-ÿ\\s\\-']+$",
      message = "Le prénom ne peut contenir que des lettres, espaces, tirets et apostrophes")
  private String prenom;

  /** Adresse email du membre */
  @Email(message = "Format d'email invalide")
  @Size(max = 100, message = "L'email ne peut pas dépasser 100 caractères")
  private String email;

  /** Numéro de téléphone du membre */
  @Pattern(regexp = "^\\+?[0-9\\s\\-\\(\\)]{8,20}$", message = "Format de téléphone invalide")
  private String telephone;

  /** Date de naissance du membre */
  @JsonFormat(pattern = "yyyy-MM-dd")
  @Past(message = "La date de naissance doit être dans le passé")
  private LocalDate dateNaissance;

  /** Adresse physique du membre */
  @Size(max = 200, message = "L'adresse ne peut pas dépasser 200 caractères")
  private String adresse;

  /** Profession du membre */
  @Size(max = 100, message = "La profession ne peut pas dépasser 100 caractères")
  private String profession;

  /** Statut matrimonial du membre */
  @Size(max = 20, message = "Le statut matrimonial ne peut pas dépasser 20 caractères")
  private String statutMatrimonial;

  /** Nationalité du membre */
  @Size(max = 50, message = "La nationalité ne peut pas dépasser 50 caractères")
  private String nationalite;

  /** Numéro de pièce d'identité */
  @Size(max = 50, message = "Le numéro d'identité ne peut pas dépasser 50 caractères")
  private String numeroIdentite;

  /** Type de pièce d'identité (CNI, Passeport, etc.) */
  @Size(max = 20, message = "Le type d'identité ne peut pas dépasser 20 caractères")
  private String typeIdentite;

  /** Statut du membre (ACTIF, INACTIF, SUSPENDU, RADIE) */
  @NotNull(message = "Le statut est obligatoire")
  @Pattern(regexp = "^(ACTIF|INACTIF|SUSPENDU|RADIE)$", message = "Statut invalide")
  private String statut;

  /** Identifiant de l'association à laquelle appartient le membre */
  @NotNull(message = "L'association est obligatoire")
  private Long associationId;

  /** Nom de l'association (lecture seule) */
  private String associationNom;

  /** Date d'adhésion du membre */
  @JsonFormat(pattern = "yyyy-MM-dd")
  private LocalDate dateAdhesion;

  /** Région géographique */
  @Size(max = 50, message = "La région ne peut pas dépasser 50 caractères")
  private String region;

  /** Ville de résidence */
  @Size(max = 50, message = "La ville ne peut pas dépasser 50 caractères")
  private String ville;

  /** Quartier de résidence */
  @Size(max = 50, message = "Le quartier ne peut pas dépasser 50 caractères")
  private String quartier;

  /** Rôle du membre dans l'organisation */
  @Size(max = 50, message = "Le rôle ne peut pas dépasser 50 caractères")
  private String role;

  /** Indique si le membre fait partie du bureau */
  private Boolean membreBureau = false;

  /** Indique si le membre est responsable */
  private Boolean responsable = false;

  /** Photo de profil (URL ou chemin) */
  @Size(max = 255, message = "L'URL de la photo ne peut pas dépasser 255 caractères")
  private String photoUrl;

  // Constructeurs
  public MembreDTO() {
    super();
    this.statut = "ACTIF";
    this.dateAdhesion = LocalDate.now();
    this.membreBureau = false;
    this.responsable = false;
  }

  public MembreDTO(String numeroMembre, String nom, String prenom, String email) {
    this();
    this.numeroMembre = numeroMembre;
    this.nom = nom;
    this.prenom = prenom;
    this.email = email;
  }

  // Getters et Setters
  public String getNumeroMembre() {
    return numeroMembre;
  }

  public void setNumeroMembre(String numeroMembre) {
    this.numeroMembre = numeroMembre;
  }

  public String getNom() {
    return nom;
  }

  public void setNom(String nom) {
    this.nom = nom;
  }

  public String getPrenom() {
    return prenom;
  }

  public void setPrenom(String prenom) {
    this.prenom = prenom;
  }

  public String getEmail() {
    return email;
  }

  public void setEmail(String email) {
    this.email = email;
  }

  public String getTelephone() {
    return telephone;
  }

  public void setTelephone(String telephone) {
    this.telephone = telephone;
  }

  public LocalDate getDateNaissance() {
    return dateNaissance;
  }

  public void setDateNaissance(LocalDate dateNaissance) {
    this.dateNaissance = dateNaissance;
  }

  public String getAdresse() {
    return adresse;
  }

  public void setAdresse(String adresse) {
    this.adresse = adresse;
  }

  public String getProfession() {
    return profession;
  }

  public void setProfession(String profession) {
    this.profession = profession;
  }

  public String getStatutMatrimonial() {
    return statutMatrimonial;
  }

  public void setStatutMatrimonial(String statutMatrimonial) {
    this.statutMatrimonial = statutMatrimonial;
  }

  public String getNationalite() {
    return nationalite;
  }

  public void setNationalite(String nationalite) {
    this.nationalite = nationalite;
  }

  public String getNumeroIdentite() {
    return numeroIdentite;
  }

  public void setNumeroIdentite(String numeroIdentite) {
    this.numeroIdentite = numeroIdentite;
  }

  public String getTypeIdentite() {
    return typeIdentite;
  }

  public void setTypeIdentite(String typeIdentite) {
    this.typeIdentite = typeIdentite;
  }

  public String getStatut() {
    return statut;
  }

  public void setStatut(String statut) {
    this.statut = statut;
  }

  public Long getAssociationId() {
    return associationId;
  }

  public void setAssociationId(Long associationId) {
    this.associationId = associationId;
  }

  public String getAssociationNom() {
    return associationNom;
  }

  public void setAssociationNom(String associationNom) {
    this.associationNom = associationNom;
  }

  public LocalDate getDateAdhesion() {
    return dateAdhesion;
  }

  public void setDateAdhesion(LocalDate dateAdhesion) {
    this.dateAdhesion = dateAdhesion;
  }

  public String getRegion() {
    return region;
  }

  public void setRegion(String region) {
    this.region = region;
  }

  public String getVille() {
    return ville;
  }

  public void setVille(String ville) {
    this.ville = ville;
  }

  public String getQuartier() {
    return quartier;
  }

  public void setQuartier(String quartier) {
    this.quartier = quartier;
  }

  public String getRole() {
    return role;
  }

  public void setRole(String role) {
    this.role = role;
  }

  public Boolean getMembreBureau() {
    return membreBureau;
  }

  public void setMembreBureau(Boolean membreBureau) {
    this.membreBureau = membreBureau;
  }

  public Boolean getResponsable() {
    return responsable;
  }

  public void setResponsable(Boolean responsable) {
    this.responsable = responsable;
  }

  public String getPhotoUrl() {
    return photoUrl;
  }

  public void setPhotoUrl(String photoUrl) {
    this.photoUrl = photoUrl;
  }

  // Méthodes utilitaires

  /**
   * Retourne le nom complet du membre (prénom + nom)
   *
   * @return Le nom complet
   */
  public String getNomComplet() {
    if (prenom != null && nom != null) {
      return prenom + " " + nom;
    } else if (nom != null) {
      return nom;
    } else if (prenom != null) {
      return prenom;
    }
    return "";
  }

  /**
   * Vérifie si le membre est majeur (18 ans ou plus)
   *
   * @return true si le membre est majeur, false sinon
   */
  public boolean isMajeur() {
    if (dateNaissance == null) {
      return false;
    }
    return LocalDate.now().minusYears(18).isAfter(dateNaissance)
        || LocalDate.now().minusYears(18).isEqual(dateNaissance);
  }

  /**
   * Calcule l'âge du membre
   *
   * @return L'âge en années, ou -1 si la date de naissance n'est pas définie
   */
  public int getAge() {
    if (dateNaissance == null) {
      return -1;
    }
    return LocalDate.now().getYear() - dateNaissance.getYear();
  }

  /**
   * Vérifie si le membre est actif
   *
   * @return true si le statut est ACTIF
   */
  public boolean isActif() {
    return "ACTIF".equals(statut);
  }

  /**
   * Vérifie si le membre a un rôle de direction
   *
   * @return true si le membre fait partie du bureau ou est responsable
   */
  public boolean hasRoleDirection() {
    return Boolean.TRUE.equals(membreBureau) || Boolean.TRUE.equals(responsable);
  }

  /**
   * Retourne une représentation textuelle du statut
   *
   * @return Le libellé du statut
   */
  public String getStatutLibelle() {
    if (statut == null) return "Non défini";

    return switch (statut) {
      case "ACTIF" -> "Actif";
      case "INACTIF" -> "Inactif";
      case "SUSPENDU" -> "Suspendu";
      case "RADIE" -> "Radié";
      default -> statut;
    };
  }

  /**
   * Valide les données essentielles du membre
   *
   * @return true si les données sont valides
   */
  public boolean isDataValid() {
    return numeroMembre != null
        && !numeroMembre.trim().isEmpty()
        && nom != null
        && !nom.trim().isEmpty()
        && prenom != null
        && !prenom.trim().isEmpty()
        && statut != null
        && !statut.trim().isEmpty()
        && associationId != null;
  }

  @Override
  public String toString() {
    return "MembreDTO{"
        + "numeroMembre='"
        + numeroMembre
        + '\''
        + ", nom='"
        + nom
        + '\''
        + ", prenom='"
        + prenom
        + '\''
        + ", email='"
        + email
        + '\''
        + ", statut='"
        + statut
        + '\''
        + ", associationId="
        + associationId
        + ", dateAdhesion="
        + dateAdhesion
        + "} "
        + super.toString();
  }
}
