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

import com.fasterxml.jackson.annotation.JsonFormat;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.Pattern;
import jakarta.validation.constraints.Size;
import java.time.LocalDate;
import java.util.List;
import java.util.UUID;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.eclipse.microprofile.openapi.annotations.media.Schema;

/**
 * DTO pour les critères de recherche avancée des membres Permet de filtrer les membres selon de
 * multiples critères
 *
 * @author UnionFlow Team
 * @version 1.0
 * @since 2025-01-19
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Schema(description = "Critères de recherche avancée pour les membres")
public class MembreSearchCriteria {

  /** Terme de recherche général (nom, prénom, email) */
  @Schema(description = "Terme de recherche général dans nom, prénom ou email", example = "marie")
  @Size(max = 100, message = "Le terme de recherche ne peut pas dépasser 100 caractères")
  private String query;

  /** Recherche par nom exact ou partiel */
  @Schema(description = "Filtre par nom (recherche partielle)", example = "Dupont")
  @Size(max = 50, message = "Le nom ne peut pas dépasser 50 caractères")
  private String nom;

  /** Recherche par prénom exact ou partiel */
  @Schema(description = "Filtre par prénom (recherche partielle)", example = "Marie")
  @Size(max = 50, message = "Le prénom ne peut pas dépasser 50 caractères")
  private String prenom;

  /** Recherche par email exact ou partiel */
  @Schema(description = "Filtre par email (recherche partielle)", example = "@unionflow.com")
  @Size(max = 100, message = "L'email ne peut pas dépasser 100 caractères")
  private String email;

  /** Filtre par numéro de téléphone */
  @Schema(description = "Filtre par numéro de téléphone", example = "+221")
  @Size(max = 20, message = "Le téléphone ne peut pas dépasser 20 caractères")
  private String telephone;

  /** Liste des IDs d'organisations */
  @Schema(description = "Liste des IDs d'organisations à inclure")
  private List<UUID> organisationIds;

  /** Liste des rôles à rechercher */
  @Schema(description = "Liste des rôles à rechercher", example = "[\"PRESIDENT\", \"SECRETAIRE\"]")
  private List<String> roles;

  /** Filtre par statut d'activité */
  @Schema(description = "Filtre par statut d'activité", example = "ACTIF")
  @Pattern(regexp = "^(ACTIF|INACTIF|SUSPENDU|RADIE)$", message = "Statut invalide")
  private String statut;

  /** Date d'adhésion minimum */
  @Schema(description = "Date d'adhésion minimum", example = "2020-01-01")
  @JsonFormat(pattern = "yyyy-MM-dd")
  private LocalDate dateAdhesionMin;

  /** Date d'adhésion maximum */
  @Schema(description = "Date d'adhésion maximum", example = "2025-12-31")
  @JsonFormat(pattern = "yyyy-MM-dd")
  private LocalDate dateAdhesionMax;

  /** Âge minimum */
  @Schema(description = "Âge minimum", example = "18")
  @Min(value = 0, message = "L'âge minimum doit être positif")
  @Max(value = 120, message = "L'âge minimum ne peut pas dépasser 120 ans")
  private Integer ageMin;

  /** Âge maximum */
  @Schema(description = "Âge maximum", example = "65")
  @Min(value = 0, message = "L'âge maximum doit être positif")
  @Max(value = 120, message = "L'âge maximum ne peut pas dépasser 120 ans")
  private Integer ageMax;

  /** Filtre par région */
  @Schema(description = "Filtre par région", example = "Dakar")
  @Size(max = 50, message = "La région ne peut pas dépasser 50 caractères")
  private String region;

  /** Filtre par ville */
  @Schema(description = "Filtre par ville", example = "Dakar")
  @Size(max = 50, message = "La ville ne peut pas dépasser 50 caractères")
  private String ville;

  /** Filtre par profession */
  @Schema(description = "Filtre par profession", example = "Ingénieur")
  @Size(max = 100, message = "La profession ne peut pas dépasser 100 caractères")
  private String profession;

  /** Filtre par nationalité */
  @Schema(description = "Filtre par nationalité", example = "Sénégalaise")
  @Size(max = 50, message = "La nationalité ne peut pas dépasser 50 caractères")
  private String nationalite;

  /** Filtre membres du bureau uniquement */
  @Schema(description = "Filtre pour les membres du bureau uniquement")
  private Boolean membreBureau;

  /** Filtre responsables uniquement */
  @Schema(description = "Filtre pour les responsables uniquement")
  private Boolean responsable;

  /** Inclure les membres inactifs dans la recherche */
  @Schema(description = "Inclure les membres inactifs", defaultValue = "false")
  @Builder.Default
  private Boolean includeInactifs = false;

  /**
   * Vérifie si au moins un critère de recherche est défini
   *
   * @return true si au moins un critère est défini
   */
  public boolean hasAnyCriteria() {
    return query != null && !query.trim().isEmpty()
        || nom != null && !nom.trim().isEmpty()
        || prenom != null && !prenom.trim().isEmpty()
        || email != null && !email.trim().isEmpty()
        || telephone != null && !telephone.trim().isEmpty()
        || organisationIds != null && !organisationIds.isEmpty()
        || roles != null && !roles.isEmpty()
        || statut != null && !statut.trim().isEmpty()
        || dateAdhesionMin != null
        || dateAdhesionMax != null
        || ageMin != null
        || ageMax != null
        || region != null && !region.trim().isEmpty()
        || ville != null && !ville.trim().isEmpty()
        || profession != null && !profession.trim().isEmpty()
        || nationalite != null && !nationalite.trim().isEmpty()
        || membreBureau != null
        || responsable != null;
  }

  /**
   * Valide la cohérence des critères de recherche
   *
   * @return true si les critères sont cohérents
   */
  public boolean isValid() {
    // Validation des dates
    if (dateAdhesionMin != null && dateAdhesionMax != null) {
      if (dateAdhesionMin.isAfter(dateAdhesionMax)) {
        return false;
      }
    }

    // Validation des âges
    if (ageMin != null && ageMax != null) {
      if (ageMin > ageMax) {
        return false;
      }
    }

    return true;
  }

  /** Nettoie les chaînes de caractères (trim et null si vide) */
  public void sanitize() {
    query = sanitizeString(query);
    nom = sanitizeString(nom);
    prenom = sanitizeString(prenom);
    email = sanitizeString(email);
    telephone = sanitizeString(telephone);
    statut = sanitizeString(statut);
    region = sanitizeString(region);
    ville = sanitizeString(ville);
    profession = sanitizeString(profession);
    nationalite = sanitizeString(nationalite);
  }

  private String sanitizeString(String str) {
    if (str == null) return null;
    str = str.trim();
    return str.isEmpty() ? null : str;
  }

  /**
   * Retourne une description textuelle des critères actifs
   *
   * @return Description des critères
   */
  public String getDescription() {
    StringBuilder sb = new StringBuilder();

    if (query != null) sb.append("Recherche: '").append(query).append("' ");
    if (nom != null) sb.append("Nom: '").append(nom).append("' ");
    if (prenom != null) sb.append("Prénom: '").append(prenom).append("' ");
    if (email != null) sb.append("Email: '").append(email).append("' ");
    if (statut != null) sb.append("Statut: ").append(statut).append(" ");
    if (organisationIds != null && !organisationIds.isEmpty()) {
      sb.append("Organisations: ").append(organisationIds.size()).append(" ");
    }
    if (roles != null && !roles.isEmpty()) {
      sb.append("Rôles: ").append(String.join(", ", roles)).append(" ");
    }
    if (dateAdhesionMin != null) sb.append("Adhésion >= ").append(dateAdhesionMin).append(" ");
    if (dateAdhesionMax != null) sb.append("Adhésion <= ").append(dateAdhesionMax).append(" ");
    if (ageMin != null) sb.append("Âge >= ").append(ageMin).append(" ");
    if (ageMax != null) sb.append("Âge <= ").append(ageMax).append(" ");
    if (region != null) sb.append("Région: '").append(region).append("' ");
    if (ville != null) sb.append("Ville: '").append(ville).append("' ");
    if (profession != null) sb.append("Profession: '").append(profession).append("' ");
    if (nationalite != null) sb.append("Nationalité: '").append(nationalite).append("' ");
    if (Boolean.TRUE.equals(membreBureau)) sb.append("Membre bureau ");
    if (Boolean.TRUE.equals(responsable)) sb.append("Responsable ");

    return sb.toString().trim();
  }
}
