package dev.lions.unionflow.server.mapper.mutuelle.epargne;

import dev.lions.unionflow.server.api.dto.mutuelle.epargne.CompteEpargneRequest;
import dev.lions.unionflow.server.api.dto.mutuelle.epargne.CompteEpargneResponse;
import dev.lions.unionflow.server.api.enums.mutuelle.epargne.StatutCompteEpargne;
import dev.lions.unionflow.server.api.enums.mutuelle.epargne.TypeCompteEpargne;
import dev.lions.unionflow.server.entity.Membre;
import dev.lions.unionflow.server.entity.Organisation;
import dev.lions.unionflow.server.entity.mutuelle.epargne.CompteEpargne;
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 CompteEpargneMapperTest {

    @Inject
    CompteEpargneMapper 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 membreId = UUID.randomUUID();
        UUID orgId = UUID.randomUUID();
        Membre membre = new Membre();
        membre.setId(membreId);
        Organisation org = new Organisation();
        org.setId(orgId);
        CompteEpargne entity = CompteEpargne.builder()
                .membre(membre)
                .organisation(org)
                .numeroCompte("MEC-00123")
                .typeCompte(TypeCompteEpargne.EPARGNE_LIBRE)
                .soldeActuel(new BigDecimal("100000"))
                .soldeBloque(BigDecimal.ZERO)
                .statut(StatutCompteEpargne.ACTIF)
                .dateOuverture(LocalDate.now())
                .description("Compte principal")
                .build();
        entity.setId(UUID.randomUUID());

        CompteEpargneResponse dto = mapper.toDto(entity);

        assertThat(dto).isNotNull();
        assertThat(dto.getMembreId()).isEqualTo(membreId.toString());
        assertThat(dto.getOrganisationId()).isEqualTo(orgId.toString());
        assertThat(dto.getNumeroCompte()).isEqualTo("MEC-00123");
        assertThat(dto.getTypeCompte()).isEqualTo(TypeCompteEpargne.EPARGNE_LIBRE);
        assertThat(dto.getSoldeActuel()).isEqualByComparingTo("100000");
        assertThat(dto.getStatut()).isEqualTo(StatutCompteEpargne.ACTIF);
        assertThat(dto.getDescription()).isEqualTo("Compte principal");
    }

    @Test
    @DisplayName("toEntity mappe Request vers entity (notesOuverture -> description)")
    void toEntity_mapsRequestToEntity() {
        CompteEpargneRequest request = new CompteEpargneRequest();
        request.setMembreId(UUID.randomUUID().toString());
        request.setOrganisationId(UUID.randomUUID().toString());
        request.setTypeCompte(TypeCompteEpargne.EPARGNE_LIBRE);
        request.setNotesOuverture("Notes à l'ouverture");

        CompteEpargne entity = mapper.toEntity(request);

        assertThat(entity).isNotNull();
        assertThat(entity.getTypeCompte()).isEqualTo(TypeCompteEpargne.EPARGNE_LIBRE);
        assertThat(entity.getDescription()).isEqualTo("Notes à l'ouverture");
        assertThat(entity.getMembre()).isNull();
        assertThat(entity.getOrganisation()).isNull();
    }

    @Test
    @DisplayName("toDto avec membre null produit membreId null (branche entityMembreId — objet null)")
    void toDto_membreNull_membreIdIsNull() {
        UUID orgId = UUID.randomUUID();
        Organisation org = new Organisation();
        org.setId(orgId);
        CompteEpargne entity = CompteEpargne.builder()
                .membre(null)
                .organisation(org)
                .numeroCompte("MEC-00999")
                .typeCompte(TypeCompteEpargne.EPARGNE_LIBRE)
                .soldeActuel(BigDecimal.ZERO)
                .soldeBloque(BigDecimal.ZERO)
                .statut(StatutCompteEpargne.ACTIF)
                .build();
        entity.setId(UUID.randomUUID());

        CompteEpargneResponse dto = mapper.toDto(entity);

        assertThat(dto).isNotNull();
        assertThat(dto.getMembreId()).isNull();
        assertThat(dto.getOrganisationId()).isEqualTo(orgId.toString());
    }

    @Test
    @DisplayName("toDto avec organisation null produit organisationId null (branche entityOrganisationId — objet null)")
    void toDto_organisationNull_organisationIdIsNull() {
        UUID membreId = UUID.randomUUID();
        Membre membre = new Membre();
        membre.setId(membreId);
        CompteEpargne entity = CompteEpargne.builder()
                .membre(membre)
                .organisation(null)
                .numeroCompte("MEC-00888")
                .typeCompte(TypeCompteEpargne.EPARGNE_BLOQUEE)
                .soldeActuel(new BigDecimal("20000"))
                .soldeBloque(BigDecimal.ZERO)
                .statut(StatutCompteEpargne.ACTIF)
                .build();
        entity.setId(UUID.randomUUID());

        CompteEpargneResponse dto = mapper.toDto(entity);

        assertThat(dto).isNotNull();
        assertThat(dto.getMembreId()).isEqualTo(membreId.toString());
        assertThat(dto.getOrganisationId()).isNull();
    }

    @Test
    @DisplayName("updateEntityFromDto met à jour l'entité cible")
    void updateEntityFromDto_updatesTarget() {
        CompteEpargne entity = CompteEpargne.builder()
                .typeCompte(TypeCompteEpargne.EPARGNE_LIBRE)
                .description("Ancienne")
                .build();
        CompteEpargneRequest request = new CompteEpargneRequest();
        request.setMembreId(UUID.randomUUID().toString());
        request.setOrganisationId(UUID.randomUUID().toString());
        request.setTypeCompte(TypeCompteEpargne.EPARGNE_BLOQUEE);
        request.setNotesOuverture("Nouvelles notes");

        mapper.updateEntityFromDto(request, entity);

        assertThat(entity.getTypeCompte()).isEqualTo(TypeCompteEpargne.EPARGNE_BLOQUEE);
        assertThat(entity.getDescription()).isEqualTo("Nouvelles notes");
    }

    @Test
    @DisplayName("updateEntityFromDto avec request null ne modifie pas l'entité (branche updateEntityFromDto — dto null)")
    void updateEntityFromDto_requestNull_entityUnchanged() {
        CompteEpargne entity = CompteEpargne.builder()
                .typeCompte(TypeCompteEpargne.EPARGNE_LIBRE)
                .description("Description stable")
                .build();

        mapper.updateEntityFromDto(null, entity);

        assertThat(entity.getTypeCompte()).isEqualTo(TypeCompteEpargne.EPARGNE_LIBRE);
        assertThat(entity.getDescription()).isEqualTo("Description stable");
    }
}
