package dev.lions.unionflow.server.api.dto.notification;

import static org.assertj.core.api.Assertions.assertThat;

import java.util.Map;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

/**
 * Tests unitaires pour ActionNotificationDTO.
 * Couvre incrementerExecutions (nombreExecutions null), getCouleurParDefaut (default),
 * getIconeParDefaut (tous les cas), constructeurs, peutEtreExecutee, utilisateurAutorise.
 *
 * @author UnionFlow Team
 * @version 1.0
 * @since 2026-02-21
 */
@DisplayName("Tests ActionNotificationDTO")
class ActionNotificationDTOTest {

  @Nested
  @DisplayName("incrementerExecutions")
  class IncrementerExecutions {

    @Test
    @DisplayName("initialise à 0 puis incrémente quand nombreExecutions null")
    void testQuandNull() {
      ActionNotificationDTO action = new ActionNotificationDTO("a", "Lib", "confirm");
      action.setNombreExecutions(null);
      action.incrementerExecutions();
      assertThat(action.getNombreExecutions()).isEqualTo(1);
    }

    @Test
    @DisplayName("incrémente quand nombreExecutions déjà défini")
    void testQuandDefini() {
      ActionNotificationDTO action = new ActionNotificationDTO("a", "Lib", "confirm");
      action.setNombreExecutions(2);
      action.incrementerExecutions();
      assertThat(action.getNombreExecutions()).isEqualTo(3);
    }
  }

  @Nested
  @DisplayName("getCouleurParDefaut")
  class GetCouleurParDefaut {

    @Test
    @DisplayName("retourne couleur si définie")
    void testCouleurDefinie() {
      ActionNotificationDTO action = new ActionNotificationDTO("a", "Lib", "confirm");
      action.setCouleur("#000000");
      assertThat(action.getCouleurParDefaut()).isEqualTo("#000000");
    }

    @Test
    @DisplayName("retourne vert pour confirm")
    void testConfirm() {
      ActionNotificationDTO action = new ActionNotificationDTO("a", "L", "confirm");
      assertThat(action.getCouleurParDefaut()).isEqualTo("#4CAF50");
    }

    @Test
    @DisplayName("retourne rouge pour cancel")
    void testCancel() {
      ActionNotificationDTO action = new ActionNotificationDTO("a", "L", "cancel");
      assertThat(action.getCouleurParDefaut()).isEqualTo("#F44336");
    }

    @Test
    @DisplayName("retourne bleu pour info")
    void testInfo() {
      ActionNotificationDTO action = new ActionNotificationDTO("a", "L", "info");
      assertThat(action.getCouleurParDefaut()).isEqualTo("#2196F3");
    }

    @Test
    @DisplayName("retourne orange pour warning")
    void testWarning() {
      ActionNotificationDTO action = new ActionNotificationDTO("a", "L", "warning");
      assertThat(action.getCouleurParDefaut()).isEqualTo("#FF9800");
    }

    @Test
    @DisplayName("retourne bleu pour url")
    void testUrl() {
      ActionNotificationDTO action = new ActionNotificationDTO("a", "L", "url");
      assertThat(action.getCouleurParDefaut()).isEqualTo("#2196F3");
    }

    @Test
    @DisplayName("retourne bleu pour route")
    void testRoute() {
      ActionNotificationDTO action = new ActionNotificationDTO("a", "L", "route");
      assertThat(action.getCouleurParDefaut()).isEqualTo("#2196F3");
    }

    @Test
    @DisplayName("retourne gris par défaut pour type inconnu")
    void testDefault() {
      ActionNotificationDTO action = new ActionNotificationDTO("a", "Lib", "unknown_type");
      assertThat(action.getCouleurParDefaut()).isEqualTo("#9E9E9E");
    }
  }

  @Nested
  @DisplayName("getIconeParDefaut")
  class GetIconeParDefaut {

    @Test
    @DisplayName("retourne icone si définie")
    void testIconeDefinie() {
      ActionNotificationDTO action = new ActionNotificationDTO("a", "Lib", "confirm");
      action.setIcone("custom");
      assertThat(action.getIconeParDefaut()).isEqualTo("custom");
    }

    @Test
    @DisplayName("retourne check pour confirm")
    void testConfirm() {
      ActionNotificationDTO action = new ActionNotificationDTO("a", "L", "confirm");
      assertThat(action.getIconeParDefaut()).isEqualTo("check");
    }

    @Test
    @DisplayName("retourne close pour cancel")
    void testCancel() {
      ActionNotificationDTO action = new ActionNotificationDTO("a", "L", "cancel");
      assertThat(action.getIconeParDefaut()).isEqualTo("close");
    }

    @Test
    @DisplayName("retourne info pour info")
    void testInfo() {
      ActionNotificationDTO action = new ActionNotificationDTO("a", "L", "info");
      assertThat(action.getIconeParDefaut()).isEqualTo("info");
    }

    @Test
    @DisplayName("retourne warning pour warning")
    void testWarning() {
      ActionNotificationDTO action = new ActionNotificationDTO("a", "L", "warning");
      assertThat(action.getIconeParDefaut()).isEqualTo("warning");
    }

    @Test
    @DisplayName("retourne open_in_new pour url")
    void testUrl() {
      ActionNotificationDTO action = new ActionNotificationDTO("a", "L", "url");
      assertThat(action.getIconeParDefaut()).isEqualTo("open_in_new");
    }

    @Test
    @DisplayName("retourne arrow_forward pour route")
    void testRoute() {
      ActionNotificationDTO action = new ActionNotificationDTO("a", "L", "route");
      assertThat(action.getIconeParDefaut()).isEqualTo("arrow_forward");
    }

    @Test
    @DisplayName("retourne phone pour call")
    void testCall() {
      ActionNotificationDTO action = new ActionNotificationDTO("a", "L", "call");
      assertThat(action.getIconeParDefaut()).isEqualTo("phone");
    }

    @Test
    @DisplayName("retourne message pour message")
    void testMessage() {
      ActionNotificationDTO action = new ActionNotificationDTO("a", "L", "message");
      assertThat(action.getIconeParDefaut()).isEqualTo("message");
    }

    @Test
    @DisplayName("retourne email pour email")
    void testEmail() {
      ActionNotificationDTO action = new ActionNotificationDTO("a", "L", "email");
      assertThat(action.getIconeParDefaut()).isEqualTo("email");
    }

    @Test
    @DisplayName("retourne share pour share")
    void testShare() {
      ActionNotificationDTO action = new ActionNotificationDTO("a", "L", "share");
      assertThat(action.getIconeParDefaut()).isEqualTo("share");
    }

    @Test
    @DisplayName("retourne touch_app pour type inconnu")
    void testDefault() {
      ActionNotificationDTO action = new ActionNotificationDTO("a", "Lib", "unknown");
      assertThat(action.getIconeParDefaut()).isEqualTo("touch_app");
    }
  }

  @Nested
  @DisplayName("Constructeurs")
  class Constructeurs {

    @Test
    @DisplayName("constructeur URL remplit url et icone")
    void testConstructeurUrl() {
      ActionNotificationDTO action = new ActionNotificationDTO("id", "Ouvrir", "http://url", "open");
      assertThat(action.getId()).isEqualTo("id");
      assertThat(action.getLibelle()).isEqualTo("Ouvrir");
      assertThat(action.getTypeAction()).isEqualTo("url");
      assertThat(action.getUrl()).isEqualTo("http://url");
      assertThat(action.getIcone()).isEqualTo("open");
    }

    @Test
    @DisplayName("constructeur route remplit route, icone et parametres")
    void testConstructeurRoute() {
      ActionNotificationDTO action = new ActionNotificationDTO(
          "id", "Aller", "/page", "arrow", Map.of("p", "v"));
      assertThat(action.getTypeAction()).isEqualTo("route");
      assertThat(action.getRoute()).isEqualTo("/page");
      assertThat(action.getIcone()).isEqualTo("arrow");
      assertThat(action.getParametres()).containsEntry("p", "v");
    }
  }

  @Nested
  @DisplayName("peutEtreExecutee")
  class PeutEtreExecutee {

    @Test
    @DisplayName("true quand estActivee et nombreExecutions < maxExecutions")
    void testPeutExecuter() {
      ActionNotificationDTO action = new ActionNotificationDTO("a", "L", "confirm");
      assertThat(action.peutEtreExecutee()).isTrue();
    }

    @Test
    @DisplayName("true quand peutEtreRepetee même si nombreExecutions >= maxExecutions")
    void testRepetee() {
      ActionNotificationDTO action = new ActionNotificationDTO("a", "L", "confirm");
      action.setNombreExecutions(1);
      action.setMaxExecutions(1);
      action.setPeutEtreRepetee(true);
      assertThat(action.peutEtreExecutee()).isTrue();
    }

    @Test
    @DisplayName("false quand nombreExecutions >= maxExecutions et peutEtreRepetee false")
    void testMaxAtteint() {
      ActionNotificationDTO action = new ActionNotificationDTO("a", "L", "confirm");
      action.setNombreExecutions(1);
      action.setMaxExecutions(1);
      action.setPeutEtreRepetee(false);
      assertThat(action.peutEtreExecutee()).isFalse();
    }

    @Test
    @DisplayName("false quand estActivee false")
    void testDesactivee() {
      ActionNotificationDTO action = new ActionNotificationDTO("a", "L", "confirm");
      action.setEstActivee(false);
      assertThat(action.peutEtreExecutee()).isFalse();
    }
  }

  @Nested
  @DisplayName("utilisateurAutorise")
  class UtilisateurAutorise {

    @Test
    @DisplayName("true quand pas de rôles ni permissions requis")
    void testSansRestriction() {
      ActionNotificationDTO action = new ActionNotificationDTO("a", "L", "confirm");
      assertThat(action.utilisateurAutorise(new String[] {}, new String[] {})).isTrue();
    }

    @Test
    @DisplayName("true quand utilisateur a le rôle requis")
    void testAvecRole() {
      ActionNotificationDTO action = new ActionNotificationDTO("a", "L", "confirm");
      action.setRolesAutorises(new String[] { "ADMIN" });
      assertThat(action.utilisateurAutorise(new String[] { "ADMIN" }, new String[] {})).isTrue();
    }

    @Test
    @DisplayName("false quand utilisateur n'a pas le rôle requis")
    void testSansRole() {
      ActionNotificationDTO action = new ActionNotificationDTO("a", "L", "confirm");
      action.setRolesAutorises(new String[] { "ADMIN" });
      assertThat(action.utilisateurAutorise(new String[] { "USER" }, new String[] {})).isFalse();
    }

    @Test
    @DisplayName("true quand utilisateur a la permission requise")
    void testAvecPermission() {
      ActionNotificationDTO action = new ActionNotificationDTO("a", "L", "confirm");
      action.setPermissionsRequises(new String[] { "write" });
      assertThat(action.utilisateurAutorise(new String[] {}, new String[] { "write" })).isTrue();
    }

    @Test
    @DisplayName("false quand utilisateur n'a pas la permission requise")
    void testSansPermission() {
      ActionNotificationDTO action = new ActionNotificationDTO("a", "L", "confirm");
      action.setPermissionsRequises(new String[] { "write" });
      assertThat(action.utilisateurAutorise(new String[] {}, new String[] { "read" })).isFalse();
    }

    @Test
    @DisplayName("true quand rolesAutorises null")
    void testRolesNull() {
      ActionNotificationDTO action = new ActionNotificationDTO("a", "L", "confirm");
      action.setRolesAutorises(null);
      assertThat(action.utilisateurAutorise(new String[] {}, new String[] {})).isTrue();
    }

    @Test
    @DisplayName("true quand permissionsRequises null")
    void testPermissionsNull() {
      ActionNotificationDTO action = new ActionNotificationDTO("a", "L", "confirm");
      action.setPermissionsRequises(null);
      assertThat(action.utilisateurAutorise(new String[] {}, new String[] {})).isTrue();
    }
  }

  @Nested
  @DisplayName("isExpiree")
  class IsExpiree {

    @Test
    @DisplayName("retourne false (non implémenté)")
    void testRetourneFalse() {
      ActionNotificationDTO action = new ActionNotificationDTO("a", "L", "confirm");
      assertThat(action.isExpiree()).isFalse();
    }
  }

  @Nested
  @DisplayName("toString")
  class ToString {

    @Test
    @DisplayName("contient id, libelle et type")
    void testToString() {
      ActionNotificationDTO action = new ActionNotificationDTO("x", "Label", "confirm");
      String s = action.toString();
      assertThat(s).contains("x");
      assertThat(s).contains("Label");
      assertThat(s).contains("confirm");
    }
  }

  @Nested
  @DisplayName("Méthodes statiques")
  class MethodesStatiques {

    @Test
    @DisplayName("creerActionConfirmation")
    void testCreerConfirmation() {
      ActionNotificationDTO a = ActionNotificationDTO.creerActionConfirmation("c1", "OK");
      assertThat(a.getId()).isEqualTo("c1");
      assertThat(a.getLibelle()).isEqualTo("OK");
      assertThat(a.getTypeAction()).isEqualTo("confirm");
      assertThat(a.getCouleur()).isEqualTo("#4CAF50");
      assertThat(a.getIcone()).isEqualTo("check");
    }

    @Test
    @DisplayName("creerActionAnnulation")
    void testCreerAnnulation() {
      ActionNotificationDTO a = ActionNotificationDTO.creerActionAnnulation("c2", "Annuler");
      assertThat(a.getTypeAction()).isEqualTo("cancel");
      assertThat(a.getEstDestructive()).isTrue();
    }

    @Test
    @DisplayName("creerActionNavigation")
    void testCreerNavigation() {
      ActionNotificationDTO a = ActionNotificationDTO.creerActionNavigation("n1", "Voir", "/detail");
      assertThat(a.getRoute()).isEqualTo("/detail");
      assertThat(a.getTypeAction()).isEqualTo("route");
    }
  }
}
