package dev.lions.unionflow.server.service;

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

import io.quarkus.test.junit.QuarkusTest;
import jakarta.inject.Inject;
import java.util.Map;
import java.util.UUID;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

@QuarkusTest
class PreferencesNotificationServiceTest {

    @Inject
    PreferencesNotificationService preferencesService;

    @Test
    @DisplayName("obtenirPreferences retourne les valeurs par défaut pour un nouvel utilisateur")
    void obtenirPreferences_returnsDefaults() {
        UUID userId = UUID.randomUUID();
        Map<String, Boolean> preferences = preferencesService.obtenirPreferences(userId);

        assertThat(preferences).isNotEmpty();
        assertThat(preferences.get("NOUVELLE_COTISATION")).isTrue();
    }

    @Test
    @DisplayName("mettreAJourPreferences modifie les préférences stockées")
    void mettreAJourPreferences_updatesStorage() {
        UUID userId = UUID.randomUUID();
        Map<String, Boolean> newPrefs = Map.of("EMAIL", false, "SMS", true);

        preferencesService.mettreAJourPreferences(userId, newPrefs);
        Map<String, Boolean> retrieved = preferencesService.obtenirPreferences(userId);

        assertThat(retrieved.get("EMAIL")).isFalse();
        assertThat(retrieved.get("SMS")).isTrue();
    }

    @Test
    @DisplayName("accepteNotification vérifie correctement une préférence spécifique")
    void accepteNotification_checksCorrectly() {
        UUID userId = UUID.randomUUID();
        preferencesService.desactiverNotification(userId, "PUSH_MOBILE");

        assertThat(preferencesService.accepteNotification(userId, "PUSH_MOBILE")).isFalse();
        assertThat(preferencesService.accepteNotification(userId, "EMAIL")).isTrue();
    }

    @Test
    @DisplayName("reinitialiserPreferences remet les valeurs par défaut")
    void reinitialiserPreferences_resetsToDefaults() {
        UUID userId = UUID.randomUUID();
        preferencesService.desactiverNotification(userId, "EMAIL");

        preferencesService.reinitialiserPreferences(userId);

        assertThat(preferencesService.accepteNotification(userId, "EMAIL")).isTrue();
    }

    @Test
    @DisplayName("activerNotification active une notification désactivée")
    void activerNotification_enablesNotification() {
        UUID userId = UUID.randomUUID();
        // D'abord désactiver
        preferencesService.desactiverNotification(userId, "SMS");
        assertThat(preferencesService.accepteNotification(userId, "SMS")).isFalse();

        // Puis activer
        preferencesService.activerNotification(userId, "SMS");

        assertThat(preferencesService.accepteNotification(userId, "SMS")).isTrue();
    }

    @Test
    @DisplayName("activerNotification sur un type inconnu retourne true (valeur par défaut)")
    void activerNotification_unknownType_returnsTrue() {
        UUID userId = UUID.randomUUID();
        preferencesService.activerNotification(userId, "TYPE_INCONNU");

        assertThat(preferencesService.accepteNotification(userId, "TYPE_INCONNU")).isTrue();
    }

    @Test
    @DisplayName("obtenirUtilisateursAcceptantNotification retourne la map des utilisateurs acceptants")
    void obtenirUtilisateursAcceptantNotification_returnsCorrectMap() {
        UUID user1 = UUID.randomUUID();
        UUID user2 = UUID.randomUUID();

        // user1 accepte EMAIL (valeur par défaut true)
        preferencesService.mettreAJourPreferences(user1, java.util.Map.of("EMAIL", true));
        // user2 refuse EMAIL
        preferencesService.desactiverNotification(user2, "EMAIL");

        java.util.Map<UUID, Boolean> result =
                preferencesService.obtenirUtilisateursAcceptantNotification("EMAIL");

        assertThat(result).isNotNull();
        // user1 doit apparaître dans les acceptants
        assertThat(result).containsKey(user1);
        // user2 ne doit pas apparaître
        assertThat(result).doesNotContainKey(user2);
    }

    @Test
    @DisplayName("obtenirUtilisateursAcceptantNotification retourne vide quand aucun utilisateur enregistré")
    void obtenirUtilisateursAcceptantNotification_noUsers_returnsEmpty() {
        // Créer un service frais (instance injectée partagée — on vérifie juste que c'est non null)
        java.util.Map<UUID, Boolean> result =
                preferencesService.obtenirUtilisateursAcceptantNotification("TYPE_SANS_PREFS");
        assertThat(result).isNotNull();
    }

    @Test
    @DisplayName("importerPreferences importe les préférences depuis la map de données")
    void importerPreferences_withValidData_updatesPreferences() {
        UUID userId = UUID.randomUUID();
        java.util.Map<String, Boolean> prefs = new java.util.HashMap<>();
        prefs.put("EMAIL", false);
        prefs.put("SMS", true);

        java.util.Map<String, Object> donnees = new java.util.HashMap<>();
        donnees.put("preferences", prefs);

        preferencesService.importerPreferences(userId, donnees);

        assertThat(preferencesService.accepteNotification(userId, "EMAIL")).isFalse();
        assertThat(preferencesService.accepteNotification(userId, "SMS")).isTrue();
    }

    @Test
    @DisplayName("importerPreferences sans clé 'preferences' ne modifie rien")
    void importerPreferences_withoutPreferencesKey_doesNothing() {
        UUID userId = UUID.randomUUID();
        // Établir un état initial connu
        preferencesService.desactiverNotification(userId, "EMAIL");

        java.util.Map<String, Object> donneesSansPrefs = new java.util.HashMap<>();
        donneesSansPrefs.put("autreChamp", "valeur");

        preferencesService.importerPreferences(userId, donneesSansPrefs);

        // EMAIL reste désactivé car aucune import n'a eu lieu
        assertThat(preferencesService.accepteNotification(userId, "EMAIL")).isFalse();
    }

    @Test
    @DisplayName("exporterPreferences retourne une map avec les clés attendues")
    void exporterPreferences_returnsMapWithExpectedKeys() {
        UUID userId = UUID.randomUUID();
        java.util.Map<String, Object> export = preferencesService.exporterPreferences(userId);

        assertThat(export).containsKeys("utilisateurId", "preferences", "dateExport");
        assertThat(export.get("utilisateurId")).isEqualTo(userId);
    }
}
