package dev.lions.utils;

import lombok.Getter;

/**
 * Enumération des opérateurs de filtrage disponibles.
 * Définit les différents types de comparaisons possibles pour le filtrage des données.
 */
@Getter
public enum FilterOperator {
  EQUALS("=", "Est égal à") {
    @Override
    public boolean apply(Object fieldValue, String filterValue) {
      return fieldValue != null && fieldValue.toString().equalsIgnoreCase(filterValue);
    }
  },
  NOT_EQUALS("!=", "Est différent de") {
    @Override
    public boolean apply(Object fieldValue, String filterValue) {
      return fieldValue == null || !fieldValue.toString().equalsIgnoreCase(filterValue);
    }
  },
  GREATER_THAN(">", "Est supérieur à") {
    @Override
    public boolean apply(Object fieldValue, String filterValue) {
      try {
        return fieldValue != null && Double.parseDouble(fieldValue.toString()) > Double.parseDouble(filterValue);
      } catch (NumberFormatException e) {
        return false;
      }
    }
  },
  LESS_THAN("<", "Est inférieur à") {
    @Override
    public boolean apply(Object fieldValue, String filterValue) {
      try {
        return fieldValue != null && Double.parseDouble(fieldValue.toString()) < Double.parseDouble(filterValue);
      } catch (NumberFormatException e) {
        return false;
      }
    }
  },
  CONTAINS("LIKE", "Contient") {
    @Override
    public boolean apply(Object fieldValue, String filterValue) {
      return fieldValue != null && fieldValue.toString().toLowerCase().contains(filterValue.toLowerCase());
    }
  },
  STARTS_WITH("STARTS", "Commence par") {
    @Override
    public boolean apply(Object fieldValue, String filterValue) {
      return fieldValue != null && fieldValue.toString().toLowerCase().startsWith(filterValue.toLowerCase());
    }
  },
  ENDS_WITH("ENDS", "Se termine par") {
    @Override
    public boolean apply(Object fieldValue, String filterValue) {
      return fieldValue != null && fieldValue.toString().toLowerCase().endsWith(filterValue.toLowerCase());
    }
  };

  private final String symbol;
  private final String label;

  FilterOperator(String symbol, String label) {
    this.symbol = symbol;
    this.label = label;
  }

  /**
   * Méthode abstraite à implémenter pour chaque opérateur.
   * Applique l'opérateur à une valeur de champ et une valeur de filtre.
   *
   * @param fieldValue  Valeur du champ à tester.
   * @param filterValue Valeur de comparaison.
   * @return Vrai si la condition est satisfaite, faux sinon.
   */
  public abstract boolean apply(Object fieldValue, String filterValue);

  /**
   * Retourne l'opérateur correspondant au symbole donné.
   * @param symbol Le symbole à rechercher
   * @return L'opérateur correspondant ou EQUALS par défaut
   */
  public static FilterOperator fromSymbol(String symbol) {
    for (FilterOperator operator : values()) {
      if (operator.symbol.equals(symbol)) {
        return operator;
      }
    }
    return EQUALS;
  }

  /**
   * Vérifie si l'opérateur est un opérateur de comparaison numérique.
   */
  public boolean isNumericComparison() {
    return this == GREATER_THAN || this == LESS_THAN;
  }

  /**
   * Vérifie si l'opérateur est un opérateur de recherche textuelle.
   */
  public boolean isTextSearch() {
    return this == CONTAINS || this == STARTS_WITH || this == ENDS_WITH;
  }
}
