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

import dev.lions.unionflow.server.api.dto.collectefonds.ContributionCollecteDTO;
import dev.lions.unionflow.server.api.enums.wave.StatutTransactionWave;
import dev.lions.unionflow.server.entity.Membre;
import dev.lions.unionflow.server.entity.collectefonds.CampagneCollecte;
import dev.lions.unionflow.server.entity.collectefonds.ContributionCollecte;
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.LocalDateTime;
import java.util.UUID;

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

@QuarkusTest
class ContributionCollecteMapperTest {

    @Inject
    ContributionCollecteMapper 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 campagneId = UUID.randomUUID();
        UUID membreId = UUID.randomUUID();
        CampagneCollecte campagne = new CampagneCollecte();
        campagne.setId(campagneId);
        Membre membre = new Membre();
        membre.setId(membreId);
        ContributionCollecte entity = ContributionCollecte.builder()
                .campagne(campagne)
                .membreDonateur(membre)
                .aliasDonateur("Donateur X")
                .estAnonyme(false)
                .montantSoutien(new BigDecimal("50000"))
                .messageSoutien("Soutien")
                .dateContribution(LocalDateTime.now())
                .statutPaiement(StatutTransactionWave.REUSSIE)
                .build();
        entity.setId(UUID.randomUUID());

        ContributionCollecteDTO dto = mapper.toDto(entity);

        assertThat(dto).isNotNull();
        assertThat(dto.getCampagneId()).isEqualTo(campagneId.toString());
        assertThat(dto.getMembreDonateurId()).isEqualTo(membreId.toString());
        assertThat(dto.getAliasDonateur()).isEqualTo("Donateur X");
        assertThat(dto.getMontantSoutien()).isEqualByComparingTo("50000");
        assertThat(dto.getStatutPaiement()).isEqualTo(StatutTransactionWave.REUSSIE);
    }

    @Test
    @DisplayName("toEntity mappe DTO vers entity")
    void toEntity_mapsDtoToEntity() {
        ContributionCollecteDTO dto = new ContributionCollecteDTO();
        dto.setAliasDonateur("Alias");
        dto.setEstAnonyme(true);
        dto.setMontantSoutien(new BigDecimal("10000"));
        dto.setMessageSoutien("Message");

        ContributionCollecte entity = mapper.toEntity(dto);

        assertThat(entity).isNotNull();
        assertThat(entity.getAliasDonateur()).isEqualTo("Alias");
        assertThat(entity.getMontantSoutien()).isEqualByComparingTo("10000");
        assertThat(entity.getCampagne()).isNull();
        assertThat(entity.getMembreDonateur()).isNull();
    }

    @Test
    @DisplayName("toDto avec campagne null produit campagneId null (branche entityCampagneId — objet null)")
    void toDto_campagneNull_campagneIdIsNull() {
        UUID membreId = UUID.randomUUID();
        Membre membre = new Membre();
        membre.setId(membreId);
        ContributionCollecte entity = ContributionCollecte.builder()
                .campagne(null)
                .membreDonateur(membre)
                .aliasDonateur("Sans campagne")
                .estAnonyme(false)
                .montantSoutien(new BigDecimal("5000"))
                .dateContribution(LocalDateTime.now())
                .build();
        entity.setId(UUID.randomUUID());

        ContributionCollecteDTO dto = mapper.toDto(entity);

        assertThat(dto).isNotNull();
        assertThat(dto.getCampagneId()).isNull();
        assertThat(dto.getMembreDonateurId()).isEqualTo(membreId.toString());
    }

    @Test
    @DisplayName("updateEntityFromDto met à jour l'entité cible")
    void updateEntityFromDto_updatesTarget() {
        ContributionCollecte entity = ContributionCollecte.builder()
                .aliasDonateur("Ancien")
                .montantSoutien(BigDecimal.ONE)
                .build();
        ContributionCollecteDTO dto = new ContributionCollecteDTO();
        dto.setAliasDonateur("Nouveau");
        dto.setMontantSoutien(new BigDecimal("25000"));

        mapper.updateEntityFromDto(dto, entity);

        assertThat(entity.getAliasDonateur()).isEqualTo("Nouveau");
        assertThat(entity.getMontantSoutien()).isEqualByComparingTo("25000");
    }

    @Test
    @DisplayName("updateEntityFromDto avec dto null ne modifie pas l'entité (branche updateEntityFromDto — dto null)")
    void updateEntityFromDto_dtoNull_entityUnchanged() {
        ContributionCollecte entity = ContributionCollecte.builder()
                .aliasDonateur("Alias stable")
                .montantSoutien(new BigDecimal("12000"))
                .build();

        mapper.updateEntityFromDto(null, entity);

        assertThat(entity.getAliasDonateur()).isEqualTo("Alias stable");
        assertThat(entity.getMontantSoutien()).isEqualByComparingTo("12000");
    }
}
