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

import dev.lions.unionflow.server.api.dto.culte.DonReligieuxDTO;
import dev.lions.unionflow.server.api.enums.culte.TypeDonReligieux;
import dev.lions.unionflow.server.entity.Membre;
import dev.lions.unionflow.server.entity.Organisation;
import dev.lions.unionflow.server.entity.culte.DonReligieux;
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.util.UUID;

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

@QuarkusTest
class DonReligieuxMapperTest {

    @Inject
    DonReligieuxMapper 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 instId = UUID.randomUUID();
        Organisation inst = new Organisation();
        inst.setId(instId);
        DonReligieux entity = DonReligieux.builder()
                .institution(inst)
                .fidele(null)
                .typeDon(TypeDonReligieux.QUETE_ORDINAIRE)
                .montant(BigDecimal.TEN)
                .build();
        entity.setId(UUID.randomUUID());

        DonReligieuxDTO dto = mapper.toDto(entity);

        assertThat(dto).isNotNull();
        assertThat(dto.getTypeDon()).isEqualTo(TypeDonReligieux.QUETE_ORDINAIRE);
        assertThat(dto.getMontant()).isEqualByComparingTo(BigDecimal.TEN);
        assertThat(dto.getInstitutionId()).isEqualTo(instId.toString());
        assertThat(dto.getFideleId()).isNull();
    }

    @Test
    @DisplayName("toEntity mappe DTO vers entity")
    void toEntity_mapsDtoToEntity() {
        DonReligieuxDTO dto = new DonReligieuxDTO();
        dto.setTypeDon(TypeDonReligieux.DIME);
        dto.setMontant(BigDecimal.valueOf(100));

        DonReligieux entity = mapper.toEntity(dto);

        assertThat(entity).isNotNull();
        assertThat(entity.getTypeDon()).isEqualTo(TypeDonReligieux.DIME);
        assertThat(entity.getMontant()).isEqualByComparingTo(BigDecimal.valueOf(100));
    }

    @Test
    @DisplayName("updateEntityFromDto met à jour les champs de l'entité")
    void updateEntityFromDto_updatesEntity() {
        DonReligieux entity = DonReligieux.builder()
                .typeDon(TypeDonReligieux.QUETE_ORDINAIRE)
                .montant(BigDecimal.ONE)
                .build();

        DonReligieuxDTO dto = new DonReligieuxDTO();
        dto.setTypeDon(TypeDonReligieux.DIME);
        dto.setMontant(BigDecimal.valueOf(500));

        mapper.updateEntityFromDto(dto, entity);

        assertThat(entity.getTypeDon()).isEqualTo(TypeDonReligieux.DIME);
        assertThat(entity.getMontant()).isEqualByComparingTo(BigDecimal.valueOf(500));
    }

    // =========================================================================
    // Branche manquante : updateEntityFromDto — dto null → early return (ligne 68)
    // =========================================================================

    @Test
    @DisplayName("updateEntityFromDto avec dto null ne modifie pas l'entité (branche null-guard)")
    void updateEntityFromDto_dtoNull_entityInchangee() {
        DonReligieux entity = DonReligieux.builder()
                .typeDon(TypeDonReligieux.QUETE_ORDINAIRE)
                .montant(BigDecimal.TEN)
                .build();

        mapper.updateEntityFromDto(null, entity);

        // L'entité ne doit pas avoir été modifiée
        assertThat(entity.getTypeDon()).isEqualTo(TypeDonReligieux.QUETE_ORDINAIRE);
        assertThat(entity.getMontant()).isEqualByComparingTo(BigDecimal.TEN);
    }

    // ==================== Tests: toDto — branches manquantes (institution null, fidele non-null) ====================

    @Test
    @DisplayName("toDto avec institution null ne renseigne pas institutionId dans le DTO")
    void toDto_institutionNull_institutionIdAbsentDuDto() {
        DonReligieux entity = DonReligieux.builder()
                .institution(null)
                .fidele(null)
                .typeDon(TypeDonReligieux.OFFRANDE_SPECIALE)
                .montant(BigDecimal.valueOf(50))
                .build();
        entity.setId(UUID.randomUUID());

        DonReligieuxDTO dto = mapper.toDto(entity);

        assertThat(dto).isNotNull();
        assertThat(dto.getInstitutionId()).isNull();
        assertThat(dto.getFideleId()).isNull();
        assertThat(dto.getTypeDon()).isEqualTo(TypeDonReligieux.OFFRANDE_SPECIALE);
        assertThat(dto.getMontant()).isEqualByComparingTo(BigDecimal.valueOf(50));
    }

    @Test
    @DisplayName("toDto avec fidele non-null renseigne fideleId dans le DTO")
    void toDto_fideleNonNull_fideleIdRenseigneDansDto() {
        UUID instId = UUID.randomUUID();
        Organisation inst = new Organisation();
        inst.setId(instId);

        UUID fideleId = UUID.randomUUID();
        Membre fidele = new Membre();
        fidele.setId(fideleId);

        DonReligieux entity = DonReligieux.builder()
                .institution(inst)
                .fidele(fidele)
                .typeDon(TypeDonReligieux.DIME)
                .montant(BigDecimal.valueOf(1000))
                .build();
        entity.setId(UUID.randomUUID());

        DonReligieuxDTO dto = mapper.toDto(entity);

        assertThat(dto).isNotNull();
        assertThat(dto.getInstitutionId()).isEqualTo(instId.toString());
        assertThat(dto.getFideleId()).isEqualTo(fideleId.toString());
        assertThat(dto.getTypeDon()).isEqualTo(TypeDonReligieux.DIME);
        assertThat(dto.getMontant()).isEqualByComparingTo(BigDecimal.valueOf(1000));
    }
}
