package dev.lions.models;

import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Pattern;
import jakarta.validation.constraints.Size;
import java.io.Serial;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * Représente un formulaire de contact.
 * Gère les demandes de contact avec validation complète des données
 * et traçabilité des soumissions.
 */
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ContactForm implements Serializable {
  @Serial
  private static final long serialVersionUID = 1L;

  private static final java.util.regex.Pattern PHONE_PATTERN = java.util.regex.Pattern.compile("^\\+?[0-9\\s-]{8,20}$");
  private static final int MAX_COMPANY_LENGTH = 100;
  private static final String DEFAULT_SUBJECT = "Demande d'information";

  @NotNull (message = "Le nom est obligatoire")
  @Size (min = 2, max = 100, message = "Le nom doit contenir entre 2 et 100 caractères")
  @Pattern(regexp = "^[\\p{L}\\s'-]+$", message = "Le nom contient des caractères non autorisés")
  private String name;

  @NotNull(message = "L'email est obligatoire")
  @Email (message = "L'email n'est pas valide")
  @Size(max = 100, message = "L'email ne doit pas dépasser 100 caractères")
  private String email;

  @NotNull(message = "Le sujet est obligatoire")
  @Size(min = 3, max = 100, message = "Le sujet doit contenir entre 3 et 100 caractères")
  private String subject;

  @NotNull(message = "Le message est obligatoire")
  @Size(min = 10, max = 1000, message = "Le message doit contenir entre 10 et 1000 caractères")
  private String message;

  @Size(max = MAX_COMPANY_LENGTH, message = "Le nom de l'entreprise ne doit pas dépasser 100 caractères")
  private String company;

  @Pattern(regexp = "^\\+?[0-9\\s-]{8,20}$", message = "Le format du numéro de téléphone n'est pas valide")
  private String phone;

  @Builder.Default
  private LocalDateTime submitDate = LocalDateTime.now();

  @Builder.Default
  private ContactStatus status = ContactStatus.NEW;

  @Builder.Default
  private Map<String, String> metadata = new HashMap<>();

  private String ipAddress;
  private String userAgent;
  private String referer;

  /**
   * Crée une instance de base du formulaire.
   *
   * @param name Nom du contact
   * @param email Email du contact
   * @param message Message du contact
   * @return Instance de ContactForm
   */
  public static ContactForm createBasic(String name, String email, String message) {
    return ContactForm.builder()
                      .name(name)
                      .email(email)
                      .subject(DEFAULT_SUBJECT)
                      .message(message)
                      .build();
  }

  /**
   * Sanitize les données du formulaire.
   * Nettoie et normalise les entrées utilisateur.
   */
  public void sanitize() {
    if (name != null) {
      name = name.trim();
    }
    if (email != null) {
      email = email.trim().toLowerCase();
    }
    if (company != null) {
      company = company.trim();
    }
    if (phone != null) {
      phone = phone.replaceAll("[^+0-9\\s-]", "");
    }
    if (message != null) {
      message = message.trim();
    }
  }

  /**
   * Vérifie si le numéro de téléphone est valide.
   *
   * @return true si le format est valide
   */
  public boolean isValidPhone() {
    return phone == null || PHONE_PATTERN.matcher(phone).matches();
  }

  /**
   * Ajoute une métadonnée au formulaire.
   *
   * @param key Clé de la métadonnée
   * @param value Valeur de la métadonnée
   */
  public void addMetadata(String key, String value) {
    if (key != null && value != null) {
      metadata.put(key, value);
    }
  }

  /**
   * Met à jour le statut du formulaire.
   *
   * @param newStatus Nouveau statut
   * @param reason Raison du changement (optionnel)
   */
  public void updateStatus(ContactStatus newStatus, String reason) {
    this.status = newStatus;
    if (reason != null) {
      addMetadata("statusChangeReason", reason);
      addMetadata("statusChangeDate", LocalDateTime.now().toString());
    }
  }

  /**
   * Vérifie si le formulaire est complet et valide.
   *
   * @return true si le formulaire est valide
   */
  public boolean isValid() {
    return name != null && !name.trim().isEmpty() &&
           email != null && email.contains("@") &&
           message != null && message.trim().length() >= 10 &&
           isValidPhone();
  }

  /**
   * Crée une représentation du formulaire pour les logs.
   *
   * @return Version sécurisée pour les logs
   */
  public String toLogString() {
    return String.format("ContactForm[name=%s, email=%s, subject=%s, timestamp=%s, status=%s]",
                         name,
                         email.replaceAll("(?<=.{3}).(?=.*@)", "*"),
                         subject,
                         submitDate,
                         status);
  }

  /**
   * Vérifie si le formulaire nécessite une attention urgente.
   *
   * @return true si urgent
   */
  public boolean isUrgent() {
    return subject != null &&
           (subject.toLowerCase().contains("urgent") ||
            message.toLowerCase().contains("urgent"));
  }
}