package dev.lions.unionflow.server.mapper.tontine;

import dev.lions.unionflow.server.api.dto.tontine.TourTontineDTO;
import dev.lions.unionflow.server.entity.Membre;
import dev.lions.unionflow.server.entity.tontine.Tontine;
import dev.lions.unionflow.server.entity.tontine.TourTontine;
import io.quarkus.test.junit.QuarkusTest;
import jakarta.inject.Inject;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.UUID;

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

@QuarkusTest
class TourTontineMapperTest {

    @Inject
    TourTontineMapper mapper;

    @Test
    @DisplayName("toDto avec null retourne null")
    void toDto_null_returnsNull() {
        assertThat(mapper.toDto(null)).isNull();
    }

    @Test
    @DisplayName("toEntity avec null retourne null")
    void toEntity_null_returnsNull() {
        assertThat(mapper.toEntity(null)).isNull();
    }

    @Test
    @DisplayName("toDto mappe entity vers DTO")
    void toDto_mapsEntityToDto() {
        UUID tontineId = UUID.randomUUID();
        UUID membreId = UUID.randomUUID();
        Tontine tontine = new Tontine();
        tontine.setId(tontineId);
        Membre membre = new Membre();
        membre.setId(membreId);
        TourTontine entity = TourTontine.builder()
                .tontine(tontine)
                .membreBeneficiaire(membre)
                .ordreTour(1)
                .dateOuvertureCotisations(LocalDate.now())
                .dateTirageOuRemise(LocalDate.now().plusDays(7))
                .montantCible(new BigDecimal("100000"))
                .cagnotteCollectee(new BigDecimal("50000"))
                .statutInterne("EN_COURS")
                .build();
        entity.setId(UUID.randomUUID());

        TourTontineDTO dto = mapper.toDto(entity);

        assertThat(dto).isNotNull();
        assertThat(dto.getTontineId()).isEqualTo(tontineId.toString());
        assertThat(dto.getMembreBeneficiaireId()).isEqualTo(membreId.toString());
        assertThat(dto.getOrdreTour()).isEqualTo(1);
        assertThat(dto.getStatutInterne()).isEqualTo("EN_COURS");
    }

    @Test
    @DisplayName("toDto avec tontine null produit tontineId null (branche entityTontineId — objet null)")
    void toDto_tontineNull_tontineIdIsNull() {
        Membre membre = new Membre();
        membre.setId(UUID.randomUUID());
        TourTontine entity = TourTontine.builder()
                .tontine(null)
                .membreBeneficiaire(membre)
                .ordreTour(2)
                .montantCible(new BigDecimal("50000"))
                .statutInterne("A_VENIR")
                .build();
        entity.setId(UUID.randomUUID());

        TourTontineDTO dto = mapper.toDto(entity);

        assertThat(dto).isNotNull();
        assertThat(dto.getTontineId()).isNull();
        assertThat(dto.getMembreBeneficiaireId()).isNotNull();
    }

    @Test
    @DisplayName("toDto avec membreBeneficiaire null produit membreBeneficiaireId null (branche entityMembreBeneficiaireId — objet null)")
    void toDto_membreBeneficiaireNull_membreBeneficiaireIdIsNull() {
        Tontine tontine = new Tontine();
        tontine.setId(UUID.randomUUID());
        TourTontine entity = TourTontine.builder()
                .tontine(tontine)
                .membreBeneficiaire(null)
                .ordreTour(3)
                .montantCible(new BigDecimal("75000"))
                .statutInterne("EN_COURS")
                .build();
        entity.setId(UUID.randomUUID());

        TourTontineDTO dto = mapper.toDto(entity);

        assertThat(dto).isNotNull();
        assertThat(dto.getTontineId()).isNotNull();
        assertThat(dto.getMembreBeneficiaireId()).isNull();
    }

    @Test
    @DisplayName("toEntity mappe DTO vers entity")
    void toEntity_mapsDtoToEntity() {
        TourTontineDTO dto = new TourTontineDTO();
        dto.setOrdreTour(2);
        dto.setDateOuvertureCotisations(LocalDate.now());
        dto.setMontantCible(new BigDecimal("200000"));
        dto.setStatutInterne("A_VENIR");

        TourTontine entity = mapper.toEntity(dto);

        assertThat(entity).isNotNull();
        assertThat(entity.getOrdreTour()).isEqualTo(2);
        assertThat(entity.getMontantCible()).isEqualByComparingTo("200000");
        assertThat(entity.getTontine()).isNull();
        assertThat(entity.getMembreBeneficiaire()).isNull();
    }

    @Test
    @DisplayName("updateEntityFromDto met à jour l'entité cible")
    void updateEntityFromDto_updatesTarget() {
        TourTontine entity = TourTontine.builder()
                .ordreTour(1)
                .statutInterne("A_VENIR")
                .build();
        TourTontineDTO dto = new TourTontineDTO();
        dto.setOrdreTour(3);
        dto.setStatutInterne("CLOTURE");

        mapper.updateEntityFromDto(dto, entity);

        assertThat(entity.getOrdreTour()).isEqualTo(3);
        assertThat(entity.getStatutInterne()).isEqualTo("CLOTURE");
    }

    @Test
    @DisplayName("updateEntityFromDto avec dto null ne modifie pas l'entité (branche updateEntityFromDto — dto null)")
    void updateEntityFromDto_dtoNull_entityUnchanged() {
        TourTontine entity = TourTontine.builder()
                .ordreTour(5)
                .statutInterne("EN_COURS")
                .montantCible(new BigDecimal("999"))
                .build();

        mapper.updateEntityFromDto(null, entity);

        assertThat(entity.getOrdreTour()).isEqualTo(5);
        assertThat(entity.getStatutInterne()).isEqualTo("EN_COURS");
        assertThat(entity.getMontantCible()).isEqualByComparingTo("999");
    }
}
