package dev.lions.unionflow.server.repository;

import dev.lions.unionflow.server.entity.BaremeCotisationRole;
import io.quarkus.hibernate.orm.panache.PanacheQuery;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import java.util.List;
import java.util.Optional;
import java.util.UUID;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.*;

@DisplayName("BaremeCotisationRoleRepository — tests unitaires")
class BaremeCotisationRoleRepositoryTest {

    static class TestableBaremeCotisationRoleRepository extends BaremeCotisationRoleRepository {
        // instanciation sans CDI
    }

    private BaremeCotisationRoleRepository repo;

    @BeforeEach
    void setUp() {
        repo = spy(new TestableBaremeCotisationRoleRepository());
    }

    @Test
    @DisplayName("classExists : instanciation possible sans CDI")
    void classExists() {
        assertThat(new TestableBaremeCotisationRoleRepository()).isNotNull();
    }

    @Test
    @DisplayName("findByOrganisationIdAndRoleOrg : retourne Optional.empty() si aucun résultat")
    @SuppressWarnings("unchecked")
    void findByOrganisationIdAndRoleOrg_noResult_returnsEmpty() {
        PanacheQuery<BaremeCotisationRole> query = mock(PanacheQuery.class);
        when(query.firstResultOptional()).thenReturn(Optional.empty());
        doReturn(query).when(repo).find(anyString(), any(UUID.class), anyString());

        Optional<BaremeCotisationRole> result =
                repo.findByOrganisationIdAndRoleOrg(UUID.randomUUID(), "TRESORIER");

        assertThat(result).isEmpty();
    }

    @Test
    @DisplayName("findByOrganisationIdAndRoleOrg : retourne le barème trouvé")
    @SuppressWarnings("unchecked")
    void findByOrganisationIdAndRoleOrg_withResult_returnsBareme() {
        BaremeCotisationRole bareme = new BaremeCotisationRole();
        PanacheQuery<BaremeCotisationRole> query = mock(PanacheQuery.class);
        when(query.firstResultOptional()).thenReturn(Optional.of(bareme));
        doReturn(query).when(repo).find(anyString(), any(UUID.class), anyString());

        Optional<BaremeCotisationRole> result =
                repo.findByOrganisationIdAndRoleOrg(UUID.randomUUID(), "PRESIDENT");

        assertThat(result).isPresent();
        assertThat(result.get()).isSameAs(bareme);
    }

    @Test
    @DisplayName("findByOrganisationId : retourne une liste vide si aucun barème")
    @SuppressWarnings("unchecked")
    void findByOrganisationId_noResult_returnsEmptyList() {
        PanacheQuery<BaremeCotisationRole> query = mock(PanacheQuery.class);
        when(query.list()).thenReturn(List.of());
        doReturn(query).when(repo).find(anyString(), any(UUID.class));

        List<BaremeCotisationRole> result = repo.findByOrganisationId(UUID.randomUUID());

        assertThat(result).isEmpty();
    }

    @Test
    @DisplayName("findByOrganisationId : retourne la liste des barèmes de l'organisation")
    @SuppressWarnings("unchecked")
    void findByOrganisationId_withResult_returnsList() {
        BaremeCotisationRole b1 = new BaremeCotisationRole();
        BaremeCotisationRole b2 = new BaremeCotisationRole();
        PanacheQuery<BaremeCotisationRole> query = mock(PanacheQuery.class);
        when(query.list()).thenReturn(List.of(b1, b2));
        doReturn(query).when(repo).find(anyString(), any(UUID.class));

        List<BaremeCotisationRole> result = repo.findByOrganisationId(UUID.randomUUID());

        assertThat(result).hasSize(2).containsExactly(b1, b2);
    }
}
