package dev.lions.unionflow.server.api.enums.analytics;

import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;

/**
 * Énumération des périodes d'analyse disponibles pour les métriques et rapports
 *
 * <p>Cette énumération définit les différentes périodes temporelles qui peuvent être utilisées pour
 * analyser les données et générer des rapports.
 *
 * @author UnionFlow Team
 * @version 1.0
 * @since 2025-01-16
 */
public enum PeriodeAnalyse {

  // === PÉRIODES COURTES ===
  AUJOURD_HUI("Aujourd'hui", "today", 1, ChronoUnit.DAYS),
  HIER("Hier", "yesterday", 1, ChronoUnit.DAYS),
  CETTE_SEMAINE("Cette semaine", "this_week", 7, ChronoUnit.DAYS),
  SEMAINE_DERNIERE("Semaine dernière", "last_week", 7, ChronoUnit.DAYS),

  // === PÉRIODES MENSUELLES ===
  CE_MOIS("Ce mois", "this_month", 1, ChronoUnit.MONTHS),
  MOIS_DERNIER("Mois dernier", "last_month", 1, ChronoUnit.MONTHS),
  TROIS_DERNIERS_MOIS("3 derniers mois", "last_3_months", 3, ChronoUnit.MONTHS),
  SIX_DERNIERS_MOIS("6 derniers mois", "last_6_months", 6, ChronoUnit.MONTHS),

  // === PÉRIODES ANNUELLES ===
  CETTE_ANNEE("Cette année", "this_year", 1, ChronoUnit.YEARS),
  ANNEE_DERNIERE("Année dernière", "last_year", 1, ChronoUnit.YEARS),
  DEUX_DERNIERES_ANNEES("2 dernières années", "last_2_years", 2, ChronoUnit.YEARS),

  // === PÉRIODES PERSONNALISÉES ===
  SEPT_DERNIERS_JOURS("7 derniers jours", "last_7_days", 7, ChronoUnit.DAYS),
  TRENTE_DERNIERS_JOURS("30 derniers jours", "last_30_days", 30, ChronoUnit.DAYS),
  QUATRE_VINGT_DIX_DERNIERS_JOURS("90 derniers jours", "last_90_days", 90, ChronoUnit.DAYS),

  // === PÉRIODES SPÉCIALES ===
  DEPUIS_CREATION("Depuis la création", "since_creation", 0, ChronoUnit.FOREVER),
  PERIODE_PERSONNALISEE("Période personnalisée", "custom", 0, ChronoUnit.DAYS);

  private final String libelle;
  private final String code;
  private final int duree;
  private final ChronoUnit unite;

  /**
   * Constructeur de l'énumération PeriodeAnalyse
   *
   * @param libelle Le libellé affiché à l'utilisateur
   * @param code Le code technique de la période
   * @param duree La durée de la période
   * @param unite L'unité de temps (jours, mois, années)
   */
  PeriodeAnalyse(String libelle, String code, int duree, ChronoUnit unite) {
    this.libelle = libelle;
    this.code = code;
    this.duree = duree;
    this.unite = unite;
  }

  /**
   * Retourne le libellé de la période
   *
   * @return Le libellé affiché à l'utilisateur
   */
  public String getLibelle() {
    return libelle;
  }

  /**
   * Retourne le code technique de la période
   *
   * @return Le code technique
   */
  public String getCode() {
    return code;
  }

  /**
   * Retourne la durée de la période
   *
   * @return La durée numérique
   */
  public int getDuree() {
    return duree;
  }

  /**
   * Retourne l'unité de temps de la période
   *
   * @return L'unité de temps (ChronoUnit)
   */
  public ChronoUnit getUnite() {
    return unite;
  }

  /**
   * Calcule la date de début pour cette période
   *
   * @return La date de début de la période
   */
  public LocalDateTime getDateDebut() {
    LocalDateTime maintenant = LocalDateTime.now();

    return switch (this) {
      case AUJOURD_HUI -> maintenant.toLocalDate().atStartOfDay();
      case HIER -> maintenant.minusDays(1).toLocalDate().atStartOfDay();
      case CETTE_SEMAINE ->
          maintenant
              .minusDays(maintenant.getDayOfWeek().getValue() - 1)
              .toLocalDate()
              .atStartOfDay();
      case SEMAINE_DERNIERE ->
          maintenant
              .minusDays(maintenant.getDayOfWeek().getValue() + 6)
              .toLocalDate()
              .atStartOfDay();
      case CE_MOIS -> maintenant.withDayOfMonth(1).toLocalDate().atStartOfDay();
      case MOIS_DERNIER -> maintenant.minusMonths(1).withDayOfMonth(1).toLocalDate().atStartOfDay();
      case CETTE_ANNEE -> maintenant.withDayOfYear(1).toLocalDate().atStartOfDay();
      case ANNEE_DERNIERE -> maintenant.minusYears(1).withDayOfYear(1).toLocalDate().atStartOfDay();
      case DEPUIS_CREATION -> LocalDateTime.of(2020, 1, 1, 0, 0); // Date de création d'UnionFlow
      case PERIODE_PERSONNALISEE -> maintenant; // À définir par l'utilisateur
      default -> maintenant.minus(duree, unite).toLocalDate().atStartOfDay();
    };
  }

  /**
   * Calcule la date de fin pour cette période
   *
   * @return La date de fin de la période
   */
  public LocalDateTime getDateFin() {
    LocalDateTime maintenant = LocalDateTime.now();

    return switch (this) {
      case AUJOURD_HUI -> maintenant.toLocalDate().atTime(23, 59, 59);
      case HIER -> maintenant.minusDays(1).toLocalDate().atTime(23, 59, 59);
      case CETTE_SEMAINE -> maintenant.toLocalDate().atTime(23, 59, 59);
      case SEMAINE_DERNIERE ->
          maintenant
              .minusDays(maintenant.getDayOfWeek().getValue())
              .toLocalDate()
              .atTime(23, 59, 59);
      case CE_MOIS -> maintenant.toLocalDate().atTime(23, 59, 59);
      case MOIS_DERNIER ->
          maintenant.withDayOfMonth(1).minusDays(1).toLocalDate().atTime(23, 59, 59);
      case CETTE_ANNEE -> maintenant.toLocalDate().atTime(23, 59, 59);
      case ANNEE_DERNIERE ->
          maintenant.withDayOfYear(1).minusDays(1).toLocalDate().atTime(23, 59, 59);
      case DEPUIS_CREATION, PERIODE_PERSONNALISEE -> maintenant;
      default -> maintenant.toLocalDate().atTime(23, 59, 59);
    };
  }

  /**
   * Vérifie si la période est une période courte (moins d'un mois)
   *
   * @return true si la période est courte
   */
  public boolean isPeriodeCourte() {
    return this == AUJOURD_HUI
        || this == HIER
        || this == CETTE_SEMAINE
        || this == SEMAINE_DERNIERE
        || this == SEPT_DERNIERS_JOURS;
  }

  /**
   * Vérifie si la période est une période longue (plus d'un an)
   *
   * @return true si la période est longue
   */
  public boolean isPeriodeLongue() {
    return this == CETTE_ANNEE
        || this == ANNEE_DERNIERE
        || this == DEUX_DERNIERES_ANNEES
        || this == DEPUIS_CREATION;
  }

  /**
   * Vérifie si la période est personnalisable
   *
   * @return true si la période peut être personnalisée
   */
  public boolean isPersonnalisable() {
    return this == PERIODE_PERSONNALISEE;
  }

  /**
   * Retourne l'intervalle de regroupement recommandé pour cette période
   *
   * @return L'intervalle de regroupement (jour, semaine, mois)
   */
  public String getIntervalleRegroupement() {
    return switch (this) {
      case AUJOURD_HUI, HIER -> "heure";
      case CETTE_SEMAINE, SEMAINE_DERNIERE, SEPT_DERNIERS_JOURS -> "jour";
      case CE_MOIS, MOIS_DERNIER, TRENTE_DERNIERS_JOURS -> "jour";
      case TROIS_DERNIERS_MOIS, SIX_DERNIERS_MOIS, QUATRE_VINGT_DIX_DERNIERS_JOURS -> "semaine";
      case CETTE_ANNEE, ANNEE_DERNIERE, DEUX_DERNIERES_ANNEES -> "mois";
      case DEPUIS_CREATION -> "annee";
      default -> "jour";
    };
  }

  /**
   * Retourne le format de date approprié pour cette période
   *
   * @return Le format de date (dd/MM, MM/yyyy, etc.)
   */
  public String getFormatDate() {
    return switch (this) {
      case AUJOURD_HUI, HIER -> "HH:mm";
      case CETTE_SEMAINE, SEMAINE_DERNIERE, SEPT_DERNIERS_JOURS -> "dd/MM";
      case CE_MOIS, MOIS_DERNIER, TRENTE_DERNIERS_JOURS -> "dd/MM";
      case TROIS_DERNIERS_MOIS, SIX_DERNIERS_MOIS, QUATRE_VINGT_DIX_DERNIERS_JOURS -> "dd/MM";
      case CETTE_ANNEE, ANNEE_DERNIERE -> "MM/yyyy";
      case DEUX_DERNIERES_ANNEES, DEPUIS_CREATION -> "yyyy";
      default -> "dd/MM/yyyy";
    };
  }
}
