package dev.lions.unionflow.server.entity;

import jakarta.persistence.*;
import jakarta.validation.constraints.*;
import java.math.BigDecimal;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;

/**
 * Entité Adresse pour la gestion des adresses des organisations, membres et
 * événements
 *
 * @author UnionFlow Team
 * @version 3.0
 * @since 2025-01-29
 */
@Entity
@Table(name = "adresses", indexes = {
    @Index(name = "idx_adresse_ville", columnList = "ville"),
    @Index(name = "idx_adresse_pays", columnList = "pays"),
    @Index(name = "idx_adresse_type", columnList = "type_adresse"),
    @Index(name = "idx_adresse_organisation", columnList = "organisation_id"),
    @Index(name = "idx_adresse_membre", columnList = "membre_id"),
    @Index(name = "idx_adresse_evenement", columnList = "evenement_id")
})
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@EqualsAndHashCode(callSuper = true)
public class Adresse extends BaseEntity {

  /** Type d'adresse (code depuis types_reference) */
  @Column(name = "type_adresse", nullable = false, length = 50)
  private String typeAdresse;

  /** Adresse complète */
  @Column(name = "adresse", length = 500)
  private String adresse;

  /** Complément d'adresse */
  @Column(name = "complement_adresse", length = 200)
  private String complementAdresse;

  /** Code postal */
  @Column(name = "code_postal", length = 20)
  private String codePostal;

  /** Ville */
  @Column(name = "ville", length = 100)
  private String ville;

  /** Région */
  @Column(name = "region", length = 100)
  private String region;

  /** Pays */
  @Column(name = "pays", length = 100)
  private String pays;

  /** Coordonnées géographiques - Latitude */
  @DecimalMin(value = "-90.0", message = "La latitude doit être comprise entre -90 et 90")
  @DecimalMax(value = "90.0", message = "La latitude doit être comprise entre -90 et 90")
  @Digits(integer = 3, fraction = 6)
  @Column(name = "latitude", precision = 9, scale = 6)
  private BigDecimal latitude;

  /** Coordonnées géographiques - Longitude */
  @DecimalMin(value = "-180.0", message = "La longitude doit être comprise entre -180 et 180")
  @DecimalMax(value = "180.0", message = "La longitude doit être comprise entre -180 et 180")
  @Digits(integer = 3, fraction = 6)
  @Column(name = "longitude", precision = 9, scale = 6)
  private BigDecimal longitude;

  /** Adresse principale (une seule par entité) */
  @Builder.Default
  @Column(name = "principale", nullable = false)
  private Boolean principale = false;

  /** Libellé personnalisé */
  @Column(name = "libelle", length = 100)
  private String libelle;

  /** Notes et commentaires */
  @Column(name = "notes", length = 500)
  private String notes;

  // Relations
  @ManyToOne(fetch = FetchType.LAZY)
  @JoinColumn(name = "organisation_id")
  private Organisation organisation;

  @ManyToOne(fetch = FetchType.LAZY)
  @JoinColumn(name = "membre_id")
  private Membre membre;

  @ManyToOne(fetch = FetchType.LAZY)
  @JoinColumn(name = "evenement_id")
  private Evenement evenement;

  /** Méthode métier pour obtenir l'adresse complète formatée */
  public String getAdresseComplete() {
    StringBuilder sb = new StringBuilder();
    if (adresse != null && !adresse.isEmpty()) {
      sb.append(adresse);
    }
    if (complementAdresse != null && !complementAdresse.isEmpty()) {
      if (sb.length() > 0)
        sb.append(", ");
      sb.append(complementAdresse);
    }
    if (codePostal != null && !codePostal.isEmpty()) {
      if (sb.length() > 0)
        sb.append(", ");
      sb.append(codePostal);
    }
    if (ville != null && !ville.isEmpty()) {
      if (sb.length() > 0)
        sb.append(" ");
      sb.append(ville);
    }
    if (region != null && !region.isEmpty()) {
      if (sb.length() > 0)
        sb.append(", ");
      sb.append(region);
    }
    if (pays != null && !pays.isEmpty()) {
      if (sb.length() > 0)
        sb.append(", ");
      sb.append(pays);
    }
    return sb.toString();
  }

  /** Méthode métier pour vérifier si l'adresse a des coordonnées GPS */
  public boolean hasCoordinates() {
    return latitude != null && longitude != null;
  }

  /** Callback JPA avant la persistance */
  protected void onCreate() {
    super.onCreate(); // Appelle le onCreate de BaseEntity
    if (principale == null) {
      principale = false;
    }
  }
}
