package dev.lions.models;

import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
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.ArrayList;
import java.util.Collections;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * Représente un service proposé par l'entreprise.
 * Cette classe définit les caractéristiques et fonctionnalités d'un service,
 * avec validation complète des données et gestion des états.
 */
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Service implements Serializable, Comparable<Service> {
  @Serial
  private static final long serialVersionUID = 1L;

  @NotNull(message = "L'identifiant du service ne peut pas être nul")
  @Pattern (regexp = "^[a-z0-9-]+$", message = "L'identifiant doit être en minuscules, avec chiffres et tirets uniquement")
  private String id;

  @NotNull(message = "Le titre du service ne peut pas être nul")
  @Size(min = 3, max = 100, message = "Le titre doit contenir entre 3 et 100 caractères")
  private String title;

  @NotNull(message = "L'icône du service ne peut pas être nulle")
  @Pattern(regexp = "^fa-[a-z0-9-]+$", message = "L'icône doit suivre le format Font Awesome (ex: fa-users)")
  private String icon;

  @NotNull(message = "La description du service ne peut pas être nulle")
  @Size(min = 10, max = 500, message = "La description doit contenir entre 10 et 500 caractères")
  private String description;

  @Size(max = 1000, message = "La description détaillée ne doit pas dépasser 1000 caractères")
  private String longDescription;

  @Builder.Default
  private List<@Size(max = 100) String> benefits = new ArrayList<>();

  @Pattern(regexp = "^/[a-z0-9-/]+$", message = "L'URL doit commencer par '/' et ne contenir que des caractères valides")
  private String detailsUrl;

  @Min (value = 0, message = "La priorité doit être positive")
  @Max (value = 100, message = "La priorité ne peut pas dépasser 100")
  @Builder.Default
  private int priority = 50;

  @Builder.Default
  private boolean isActive = true;

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

  private LocalDateTime updatedAt;

  @Pattern(regexp = "^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$", message = "La couleur doit être au format hexadécimal")
  @Builder.Default
  private String accentColor = "#2196F3";

  /**
   * Crée un service de base avec les champs obligatoires.
   *
   * @param title Titre du service
   * @param icon Icône du service
   * @param description Description du service
   * @param benefits Liste des avantages
   * @param detailsUrl URL des détails
   * @return Instance de Service
   */
  public static Service createBasicService(String title, String icon, String description,
                                           List<String> benefits, String detailsUrl) {
    String id = title.toLowerCase()
                     .replaceAll("[^a-z0-9-]", "-")
                     .replaceAll("-+", "-");

    return Service.builder()
                  .id(id)
                  .title(title)
                  .icon(icon)
                  .description(description)
                  .benefits(benefits != null ? new ArrayList<>(benefits) : new ArrayList<>())
                  .detailsUrl(detailsUrl)
                  .build();
  }

  /**
   * Ajoute un avantage à la liste des bénéfices.
   *
   * @param benefit Avantage à ajouter
   * @return true si l'ajout a réussi
   */
  public boolean addBenefit(String benefit) {
    if (benefit != null && !benefit.isEmpty() && benefit.length() <= 100) {
      return benefits.add(benefit.trim());
    }
    return false;
  }

  /**
   * Récupère la liste immuable des avantages.
   *
   * @return Liste des avantages
   */
  public List<String> getBenefits() {
    return Collections.unmodifiableList(benefits);
  }

  /**
   * Met à jour la date de modification.
   */
  public void touch() {
    this.updatedAt = LocalDateTime.now();
  }

  /**
   * Active ou désactive le service.
   *
   * @param active Nouvel état
   */
  public void setActive(boolean active) {
    this.isActive = active;
    touch();
  }

  /**
   * Vérifie si le service est complet et valide.
   *
   * @return true si le service est valide
   */
  public boolean isValid() {
    return id != null && !id.isEmpty() &&
           title != null && !title.isEmpty() &&
           icon != null && !icon.isEmpty() &&
           description != null && !description.isEmpty();
  }

  /**
   * Implémente la comparaison pour le tri par priorité.
   */
  @Override
  public int compareTo(Service other) {
    return Integer.compare(this.priority, other.priority);
  }

  /**
   * Construit une représentation HTML sûre de l'icône.
   *
   * @return Balise HTML de l'icône
   */
  public String getIconHtml() {
    return String.format("<i class=\"fas %s\" aria-hidden=\"true\"></i>",
                         icon.replaceAll("[^a-zA-Z0-9-]", ""));
  }

  /**
   * Génère un identifiant unique basé sur le titre.
   */
  public void generateId() {
    if (this.id == null || this.id.isEmpty()) {
      this.id = this.title.toLowerCase()
                          .replaceAll("[^a-z0-9-]", "-")
                          .replaceAll("-+", "-");
    }
  }
}