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

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

import java.util.List;
import java.util.UUID;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import dev.lions.unionflow.server.api.dto.membre.response.MembreSummaryResponse;

/**
 * Tests unitaires pour MembreSearchResultDTO.
 * Couvre toutes les branches : calculatePaginationFlags, isEmpty, getResultDescription,
 * getNextPageNumber, getPreviousPageNumber, empty (2 surcharges).
 *
 * @author UnionFlow Team
 * @version 1.0
 * @since 2026-02-21
 */
@DisplayName("Tests MembreSearchResultDTO")
class MembreSearchResultDTOTest {

  private static MembreSummaryResponse unMembre() {
    return new MembreSummaryResponse(
        UUID.randomUUID(), null, "Prenom", "Nom", null, null, null, null, null, null, true, List.of(), null, null);
  }

  @Nested
  @DisplayName("calculatePaginationFlags")
  class CalculatePaginationFlags {

    @Test
    @DisplayName("isFirst true quand currentPage 0")
    void testFirstPage() {
      MembreSearchResultDTO r = new MembreSearchResultDTO();
      r.setCurrentPage(0);
      r.setTotalPages(5);
      r.setMembres(List.of(unMembre()));
      r.calculatePaginationFlags();
      assertThat(r.isFirst()).isTrue();
      assertThat(r.isHasPrevious()).isFalse();
    }

    @Test
    @DisplayName("isLast true quand currentPage dernière")
    void testLastPage() {
      MembreSearchResultDTO r = new MembreSearchResultDTO();
      r.setCurrentPage(4);
      r.setTotalPages(5);
      r.setMembres(List.of(unMembre()));
      r.calculatePaginationFlags();
      assertThat(r.isLast()).isTrue();
      assertThat(r.isHasNext()).isFalse();
    }

    @Test
    @DisplayName("numberOfElements 0 quand membres null")
    void testMembresNull() {
      MembreSearchResultDTO r = new MembreSearchResultDTO();
      r.setMembres(null);
      r.setCurrentPage(0);
      r.setTotalPages(1);
      r.calculatePaginationFlags();
      assertThat(r.getNumberOfElements()).isEqualTo(0);
    }

    @Test
    @DisplayName("numberOfElements = size quand membres non null")
    void testMembresNonVide() {
      MembreSearchResultDTO r = new MembreSearchResultDTO();
      r.setMembres(List.of(unMembre(), unMembre()));
      r.setCurrentPage(0);
      r.setTotalPages(1);
      r.calculatePaginationFlags();
      assertThat(r.getNumberOfElements()).isEqualTo(2);
    }
  }

  @Nested
  @DisplayName("isEmpty")
  class IsEmpty {

    @Test
    @DisplayName("true quand membres null")
    void testMembresNull() {
      MembreSearchResultDTO r = new MembreSearchResultDTO();
      r.setMembres(null);
      assertThat(r.isEmpty()).isTrue();
    }

    @Test
    @DisplayName("true quand membres vide")
    void testMembresVide() {
      MembreSearchResultDTO r = new MembreSearchResultDTO();
      r.setMembres(List.of());
      assertThat(r.isEmpty()).isTrue();
    }

    @Test
    @DisplayName("false quand membres non vide")
    void testMembresNonVide() {
      MembreSearchResultDTO r = new MembreSearchResultDTO();
      r.setMembres(List.of(unMembre()));
      assertThat(r.isEmpty()).isFalse();
    }
  }

  @Nested
  @DisplayName("getResultDescription")
  class GetResultDescription {

    @Test
    @DisplayName("Aucun membre trouvé quand vide")
    void testVide() {
      MembreSearchResultDTO r = new MembreSearchResultDTO();
      r.setMembres(List.of());
      r.setTotalElements(0);
      assertThat(r.getResultDescription()).isEqualTo("Aucun membre trouvé");
    }

    @Test
    @DisplayName("1 membre trouvé quand totalElements 1")
    void testUnSeul() {
      MembreSearchResultDTO r = new MembreSearchResultDTO();
      r.setMembres(List.of(unMembre()));
      r.setTotalElements(1);
      r.setTotalPages(1);
      r.setCurrentPage(0);
      r.setPageSize(20);
      r.setNumberOfElements(1);
      assertThat(r.getResultDescription()).isEqualTo("1 membre trouvé");
    }

    @Test
    @DisplayName("X membres trouvés quand une seule page")
    void testUnePage() {
      MembreSearchResultDTO r = new MembreSearchResultDTO();
      r.setMembres(List.of(unMembre(), unMembre()));
      r.setTotalElements(2);
      r.setTotalPages(1);
      r.setCurrentPage(0);
      r.setPageSize(20);
      r.setNumberOfElements(2);
      assertThat(r.getResultDescription()).isEqualTo("2 membres trouvés");
    }

    @Test
    @DisplayName("Membres X-Y sur Z quand plusieurs pages")
    void testPlusieursPages() {
      MembreSearchResultDTO r = new MembreSearchResultDTO();
      r.setMembres(List.of(unMembre(), unMembre()));
      r.setTotalElements(50);
      r.setTotalPages(5);
      r.setCurrentPage(1);
      r.setPageSize(20);
      r.setNumberOfElements(2);
      r.calculatePaginationFlags();
      String d = r.getResultDescription();
      assertThat(d).contains("21");
      assertThat(d).contains("22");
      assertThat(d).contains("50");
      assertThat(d).contains("2");
      assertThat(d).contains("5");
    }
  }

  @Nested
  @DisplayName("getNextPageNumber")
  class GetNextPageNumber {

    @Test
    @DisplayName("retourne currentPage+2 (1-based) quand hasNext true")
    void testHasNext() {
      MembreSearchResultDTO r = new MembreSearchResultDTO();
      r.setHasNext(true);
      r.setCurrentPage(0);
      assertThat(r.getNextPageNumber()).isEqualTo(2);
    }

    @Test
    @DisplayName("retourne -1 quand hasNext false")
    void testNoNext() {
      MembreSearchResultDTO r = new MembreSearchResultDTO();
      r.setHasNext(false);
      assertThat(r.getNextPageNumber()).isEqualTo(-1);
    }
  }

  @Nested
  @DisplayName("getPreviousPageNumber")
  class GetPreviousPageNumber {

    @Test
    @DisplayName("retourne currentPage (1-based) quand hasPrevious true")
    void testHasPrevious() {
      MembreSearchResultDTO r = new MembreSearchResultDTO();
      r.setHasPrevious(true);
      r.setCurrentPage(2);
      assertThat(r.getPreviousPageNumber()).isEqualTo(2);
    }

    @Test
    @DisplayName("retourne -1 quand hasPrevious false")
    void testNoPrevious() {
      MembreSearchResultDTO r = new MembreSearchResultDTO();
      r.setHasPrevious(false);
      assertThat(r.getPreviousPageNumber()).isEqualTo(-1);
    }
  }

  @Nested
  @DisplayName("empty")
  class Empty {

    @Test
    @DisplayName("empty(criteria) utilise pageSize 20 et currentPage 0")
    void testEmptyAvecCriteria() {
      MembreSearchCriteria criteria = MembreSearchCriteria.builder().query("x").build();
      MembreSearchResultDTO r = MembreSearchResultDTO.empty(criteria);
      assertThat(r.getMembres()).isEmpty();
      assertThat(r.getTotalElements()).isEqualTo(0);
      assertThat(r.getPageSize()).isEqualTo(20);
      assertThat(r.getCurrentPage()).isEqualTo(0);
      assertThat(r.isFirst()).isTrue();
      assertThat(r.isLast()).isTrue();
      assertThat(r.getCriteria()).isEqualTo(criteria);
      assertThat(r.getStatistics()).isNotNull();
    }

    @Test
    @DisplayName("empty(criteria, pageSize, currentPage) remplit tous les champs")
    void testEmptyAvecPageSize() {
      MembreSearchCriteria criteria = MembreSearchCriteria.builder().nom("Dupont").build();
      MembreSearchResultDTO r = MembreSearchResultDTO.empty(criteria, 10, 0);
      assertThat(r.getPageSize()).isEqualTo(10);
      assertThat(r.getCurrentPage()).isEqualTo(0);
      assertThat(r.getTotalPages()).isEqualTo(0);
      assertThat(r.getNumberOfElements()).isEqualTo(0);
      assertThat(r.getStatistics().getMembresActifs()).isEqualTo(0);
    }
  }
}
