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

import static dev.lions.unionflow.server.api.TestDataFactory.createDashboardDataDTO;
import static dev.lions.unionflow.server.api.TestDataFactory.createRecentActivityDTO;
import static dev.lions.unionflow.server.api.TestDataFactory.createUpcomingEventDTO;
import static dev.lions.unionflow.server.api.TestDataFactory.daysFromNow;
import static dev.lions.unionflow.server.api.TestDataFactory.hoursAgo;
import static dev.lions.unionflow.server.api.TestDataFactory.now;
import static org.assertj.core.api.Assertions.assertThat;

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

@DisplayName("Tests pour DashboardDataDTO")
class DashboardDataDTOTest {

  @Test
  @DisplayName("Test de base - classe peut être instanciée")
  void testClasseInstanciable() {
    DashboardDataDTO dto = new DashboardDataDTO();
    assertThat(dto).isNotNull();
  }

  @Nested
  @DisplayName("Tests de construction")
  class ConstructionTests {

    @Test
    @DisplayName("Constructeur par défaut")
    void testConstructeurParDefaut() {
      DashboardDataDTO dto = new DashboardDataDTO();

      assertThat(dto).isNotNull();
    }

    @Test
    @DisplayName("Builder pattern")
    void testBuilder() {
      DashboardStatsDTO stats = DashboardStatsDTO.builder().build();
      List<RecentActivityDTO> activities = List.of();
      List<UpcomingEventDTO> events = List.of();
      Map<String, Object> preferences = new HashMap<>();

      DashboardDataDTO dto = DashboardDataDTO.builder()
          .stats(stats)
          .recentActivities(activities)
          .upcomingEvents(events)
          .userPreferences(preferences)
          .organizationId("org-123")
          .userId("user-456")
          .build();

      assertThat(dto.getStats()).isEqualTo(stats);
      assertThat(dto.getRecentActivities()).isEqualTo(activities);
      assertThat(dto.getUpcomingEvents()).isEqualTo(events);
      assertThat(dto.getUserPreferences()).isEqualTo(preferences);
      assertThat(dto.getOrganizationId()).isEqualTo("org-123");
      assertThat(dto.getUserId()).isEqualTo("user-456");
    }
  }

  @Nested
  @DisplayName("Tests getTodayEventsCount")
  class GetTodayEventsCountTests {

    @Test
    @DisplayName("getTodayEventsCount - avec événements d'aujourd'hui")
    void testGetTodayEventsCountAvecEvenementsAujourdhui() {
      UpcomingEventDTO event1 = createUpcomingEventDTO(now());
      UpcomingEventDTO event2 = createUpcomingEventDTO(daysFromNow(1));
      UpcomingEventDTO event3 = createUpcomingEventDTO(now());

      DashboardDataDTO dto = DashboardDataDTO.builder()
          .upcomingEvents(List.of(event1, event2, event3))
          .build();

      assertThat(dto.getTodayEventsCount()).isEqualTo(2);
    }

    @Test
    @DisplayName("getTodayEventsCount - sans événements d'aujourd'hui")
    void testGetTodayEventsCountSansEvenementsAujourdhui() {
      UpcomingEventDTO event = createUpcomingEventDTO(daysFromNow(1));

      DashboardDataDTO dto = DashboardDataDTO.builder()
          .upcomingEvents(List.of(event))
          .build();

      assertThat(dto.getTodayEventsCount()).isEqualTo(0);
    }

    @Test
    @DisplayName("getTodayEventsCount - upcomingEvents null")
    void testGetTodayEventsCountNull() {
      DashboardDataDTO dto = new DashboardDataDTO();

      assertThat(dto.getTodayEventsCount()).isEqualTo(0);
    }
  }

  @Nested
  @DisplayName("Tests getTomorrowEventsCount")
  class GetTomorrowEventsCountTests {

    @Test
    @DisplayName("getTomorrowEventsCount - avec événements de demain")
    void testGetTomorrowEventsCountAvecEvenementsDemain() {
      UpcomingEventDTO event1 = createUpcomingEventDTO(daysFromNow(1));
      UpcomingEventDTO event2 = createUpcomingEventDTO(daysFromNow(2));

      DashboardDataDTO dto = DashboardDataDTO.builder()
          .upcomingEvents(List.of(event1, event2))
          .build();

      assertThat(dto.getTomorrowEventsCount()).isEqualTo(1);
    }

    @Test
    @DisplayName("getTomorrowEventsCount - upcomingEvents null")
    void testGetTomorrowEventsCountNull() {
      DashboardDataDTO dto = new DashboardDataDTO();

      assertThat(dto.getTomorrowEventsCount()).isEqualTo(0);
    }
  }

  @Nested
  @DisplayName("Tests getRecentActivitiesCount")
  class GetRecentActivitiesCountTests {

    @Test
    @DisplayName("getRecentActivitiesCount - avec activités récentes")
    void testGetRecentActivitiesCountAvecActivitesRecent() {
      RecentActivityDTO activity1 = createRecentActivityDTO("member", hoursAgo(12));
      RecentActivityDTO activity2 = createRecentActivityDTO("event", hoursAgo(25));
      RecentActivityDTO activity3 = createRecentActivityDTO("contribution", hoursAgo(5));

      DashboardDataDTO dto = DashboardDataDTO.builder()
          .recentActivities(List.of(activity1, activity2, activity3))
          .build();

      assertThat(dto.getRecentActivitiesCount()).isEqualTo(2);
    }

    @Test
    @DisplayName("getRecentActivitiesCount - recentActivities null")
    void testGetRecentActivitiesCountNull() {
      DashboardDataDTO dto = new DashboardDataDTO();

      assertThat(dto.getRecentActivitiesCount()).isEqualTo(0);
    }
  }

  @Nested
  @DisplayName("Tests getTodayActivitiesCount")
  class GetTodayActivitiesCountTests {

    @Test
    @DisplayName("getTodayActivitiesCount - avec activités d'aujourd'hui")
    void testGetTodayActivitiesCountAvecActivitesAujourdhui() {
      RecentActivityDTO activity1 = createRecentActivityDTO("member", now());
      RecentActivityDTO activity2 = createRecentActivityDTO("event", hoursAgo(25));

      DashboardDataDTO dto = DashboardDataDTO.builder()
          .recentActivities(List.of(activity1, activity2))
          .build();

      assertThat(dto.getTodayActivitiesCount()).isEqualTo(1);
    }

    @Test
    @DisplayName("getTodayActivitiesCount - recentActivities null")
    void testGetTodayActivitiesCountNull() {
      DashboardDataDTO dto = new DashboardDataDTO();

      assertThat(dto.getTodayActivitiesCount()).isEqualTo(0);
    }
  }

  @Nested
  @DisplayName("Tests getHasUpcomingEvents")
  class GetHasUpcomingEventsTests {

    @Test
    @DisplayName("getHasUpcomingEvents - avec événements")
    void testGetHasUpcomingEventsAvecEvenements() {
      DashboardDataDTO dto = DashboardDataDTO.builder()
          .upcomingEvents(List.of(createUpcomingEventDTO()))
          .build();

      assertThat(dto.getHasUpcomingEvents()).isTrue();
    }

    @Test
    @DisplayName("getHasUpcomingEvents - liste vide")
    void testGetHasUpcomingEventsListeVide() {
      DashboardDataDTO dto = DashboardDataDTO.builder()
          .upcomingEvents(List.of())
          .build();

      assertThat(dto.getHasUpcomingEvents()).isFalse();
    }

    @Test
    @DisplayName("getHasUpcomingEvents - null")
    void testGetHasUpcomingEventsNull() {
      DashboardDataDTO dto = new DashboardDataDTO();

      assertThat(dto.getHasUpcomingEvents()).isFalse();
    }
  }

  @Nested
  @DisplayName("Tests getHasRecentActivities")
  class GetHasRecentActivitiesTests {

    @Test
    @DisplayName("getHasRecentActivities - avec activités")
    void testGetHasRecentActivitiesAvecActivites() {
      DashboardDataDTO dto = DashboardDataDTO.builder()
          .recentActivities(List.of(createRecentActivityDTO()))
          .build();

      assertThat(dto.getHasRecentActivities()).isTrue();
    }

    @Test
    @DisplayName("getHasRecentActivities - liste vide")
    void testGetHasRecentActivitiesListeVide() {
      DashboardDataDTO dto = DashboardDataDTO.builder()
          .recentActivities(List.of())
          .build();

      assertThat(dto.getHasRecentActivities()).isFalse();
    }

    @Test
    @DisplayName("getHasRecentActivities - null")
    void testGetHasRecentActivitiesNull() {
      DashboardDataDTO dto = new DashboardDataDTO();

      assertThat(dto.getHasRecentActivities()).isFalse();
    }
  }

  @Nested
  @DisplayName("Tests des préférences utilisateur")
  class UserPreferencesTests {

    @Test
    @DisplayName("getThemePreference - avec préférence")
    void testGetThemePreferenceAvecPreference() {
      Map<String, Object> preferences = new HashMap<>();
      preferences.put("theme", "dark");

      DashboardDataDTO dto = DashboardDataDTO.builder()
          .userPreferences(preferences)
          .build();

      assertThat(dto.getThemePreference()).isEqualTo("dark");
    }

    @Test
    @DisplayName("getThemePreference - sans préférence")
    void testGetThemePreferenceSansPreference() {
      DashboardDataDTO dto = new DashboardDataDTO();

      assertThat(dto.getThemePreference()).isEqualTo("royal_teal");
    }

    @Test
    @DisplayName("getLanguagePreference - avec préférence")
    void testGetLanguagePreferenceAvecPreference() {
      Map<String, Object> preferences = new HashMap<>();
      preferences.put("language", "en");

      DashboardDataDTO dto = DashboardDataDTO.builder()
          .userPreferences(preferences)
          .build();

      assertThat(dto.getLanguagePreference()).isEqualTo("en");
    }

    @Test
    @DisplayName("getLanguagePreference - sans préférence")
    void testGetLanguagePreferenceSansPreference() {
      DashboardDataDTO dto = new DashboardDataDTO();

      assertThat(dto.getLanguagePreference()).isEqualTo("fr");
    }

    @Test
    @DisplayName("getNotificationsEnabled - avec préférence")
    void testGetNotificationsEnabledAvecPreference() {
      Map<String, Object> preferences = new HashMap<>();
      preferences.put("notifications", false);

      DashboardDataDTO dto = DashboardDataDTO.builder()
          .userPreferences(preferences)
          .build();

      assertThat(dto.getNotificationsEnabled()).isFalse();
    }

    @Test
    @DisplayName("getNotificationsEnabled - sans préférence")
    void testGetNotificationsEnabledSansPreference() {
      DashboardDataDTO dto = new DashboardDataDTO();

      assertThat(dto.getNotificationsEnabled()).isTrue();
    }

    @Test
    @DisplayName("getAutoRefreshEnabled - avec préférence")
    void testGetAutoRefreshEnabledAvecPreference() {
      Map<String, Object> preferences = new HashMap<>();
      preferences.put("autoRefresh", false);

      DashboardDataDTO dto = DashboardDataDTO.builder()
          .userPreferences(preferences)
          .build();

      assertThat(dto.getAutoRefreshEnabled()).isFalse();
    }

    @Test
    @DisplayName("getAutoRefreshEnabled - sans préférence")
    void testGetAutoRefreshEnabledSansPreference() {
      DashboardDataDTO dto = new DashboardDataDTO();

      assertThat(dto.getAutoRefreshEnabled()).isTrue();
    }

    @Test
    @DisplayName("getRefreshInterval - avec préférence")
    void testGetRefreshIntervalAvecPreference() {
      Map<String, Object> preferences = new HashMap<>();
      preferences.put("refreshInterval", 600);

      DashboardDataDTO dto = DashboardDataDTO.builder()
          .userPreferences(preferences)
          .build();

      assertThat(dto.getRefreshInterval()).isEqualTo(600);
    }

    @Test
    @DisplayName("getRefreshInterval - sans préférence")
    void testGetRefreshIntervalSansPreference() {
      DashboardDataDTO dto = new DashboardDataDTO();

      assertThat(dto.getRefreshInterval()).isEqualTo(300);
    }
  }
}

