package dev.lions.unionflow.server.mapper;

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

import dev.lions.unionflow.server.api.dto.solidarite.request.CreateDemandeAideRequest;
import dev.lions.unionflow.server.api.dto.solidarite.request.UpdateDemandeAideRequest;
import dev.lions.unionflow.server.api.dto.solidarite.response.DemandeAideResponse;
import dev.lions.unionflow.server.api.enums.solidarite.PrioriteAide;
import dev.lions.unionflow.server.api.enums.solidarite.StatutAide;
import dev.lions.unionflow.server.api.enums.solidarite.TypeAide;
import dev.lions.unionflow.server.entity.DemandeAide;
import dev.lions.unionflow.server.entity.Membre;
import dev.lions.unionflow.server.entity.Organisation;
import io.quarkus.test.junit.QuarkusTest;
import jakarta.inject.Inject;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.UUID;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

@QuarkusTest
class DemandeAideMapperTest {

    @Inject
    DemandeAideMapper mapper;

    // ================================================================
    // toDTO
    // ================================================================

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

    @Test
    @DisplayName("toDTO mappe entité vers response")
    void toDTO_mapsEntityToResponse() {
        DemandeAide entity = new DemandeAide();
        entity.setId(UUID.randomUUID());
        entity.setTitre("Demande test");
        entity.setDescription("Description");
        entity.setStatut(StatutAide.EN_ATTENTE);
        entity.setDemandeur(null);
        entity.setOrganisation(null);
        entity.setEvaluateur(null);

        DemandeAideResponse dto = mapper.toDTO(entity);

        assertThat(dto).isNotNull();
        assertThat(dto.getId()).isEqualTo(entity.getId());
        assertThat(dto.getTitre()).isEqualTo("Demande test");
        assertThat(dto.getDescription()).isEqualTo("Description");
        assertThat(dto.getStatut()).isEqualTo(StatutAide.EN_ATTENTE);
    }

    @Test
    @DisplayName("toDTO avec urgence null mappe PrioriteAide.NORMALE (branche null L50)")
    void toDTO_urgenceNull_mappesNormale() {
        DemandeAide entity = new DemandeAide();
        entity.setId(UUID.randomUUID());
        entity.setTitre("Test urgence null");
        entity.setDescription("Desc");
        entity.setStatut(StatutAide.EN_ATTENTE);
        entity.setUrgence(null); // urgence == null → PrioriteAide.NORMALE

        DemandeAideResponse dto = mapper.toDTO(entity);

        assertThat(dto.getPriorite()).isEqualTo(PrioriteAide.NORMALE);
    }

    @Test
    @DisplayName("toDTO avec urgence=true mappe PrioriteAide.URGENTE")
    void toDTO_urgenceTrue_mappesUrgente() {
        DemandeAide entity = new DemandeAide();
        entity.setId(UUID.randomUUID());
        entity.setTitre("Test urgence true");
        entity.setDescription("Desc");
        entity.setStatut(StatutAide.EN_ATTENTE);
        entity.setUrgence(true);

        DemandeAideResponse dto = mapper.toDTO(entity);

        assertThat(dto.getPriorite()).isEqualTo(PrioriteAide.URGENTE);
    }

    @Test
    @DisplayName("toDTO avec évaluateur non null mappe les champs évaluateur (L59-61)")
    void toDTO_evaluateurNonNull_mappeEvaluateur() {
        Membre evaluateur = new Membre();
        evaluateur.setId(UUID.randomUUID());
        evaluateur.setPrenom("Marie");
        evaluateur.setNom("Curie");

        DemandeAide entity = new DemandeAide();
        entity.setId(UUID.randomUUID());
        entity.setTitre("Test évaluateur");
        entity.setDescription("Desc");
        entity.setStatut(StatutAide.EN_COURS_EVALUATION);
        entity.setEvaluateur(evaluateur);

        DemandeAideResponse dto = mapper.toDTO(entity);

        assertThat(dto.getEvaluateurId()).isEqualTo(evaluateur.getId().toString());
        assertThat(dto.getEvaluateurNom()).isEqualTo("Marie Curie");
    }

    @Test
    @DisplayName("toDTO avec demandeur et organisation non null mappe tous les champs")
    void toDTO_demandeurEtOrganisationNonNull_mappeTousLesChamps() {
        Membre demandeur = new Membre();
        demandeur.setId(UUID.randomUUID());
        demandeur.setPrenom("Jean");
        demandeur.setNom("Dupont");
        demandeur.setNumeroMembre("M-001");

        Organisation organisation = new Organisation();
        organisation.setId(UUID.randomUUID());
        organisation.setNom("Asso Solidaire");

        DemandeAide entity = new DemandeAide();
        entity.setId(UUID.randomUUID());
        entity.setTitre("Test complet");
        entity.setDescription("Desc");
        entity.setStatut(StatutAide.EN_ATTENTE);
        entity.setDemandeur(demandeur);
        entity.setOrganisation(organisation);

        DemandeAideResponse dto = mapper.toDTO(entity);

        assertThat(dto.getMembreDemandeurId()).isEqualTo(demandeur.getId());
        assertThat(dto.getNomDemandeur()).isEqualTo("Jean Dupont");
        assertThat(dto.getNumeroMembreDemandeur()).isEqualTo("M-001");
        assertThat(dto.getAssociationId()).isEqualTo(organisation.getId());
        assertThat(dto.getNomAssociation()).isEqualTo("Asso Solidaire");
    }

    // ================================================================
    // updateEntityFromDTO
    // ================================================================

    @Test
    @DisplayName("updateEntityFromDTO avec entity null retourne sans exception (L75)")
    void updateEntityFromDTO_entityNull_returnsWithoutException() {
        UpdateDemandeAideRequest request = UpdateDemandeAideRequest.builder()
                .titre("Titre")
                .build();
        // No exception should be thrown
        mapper.updateEntityFromDTO(null, request);
    }

    @Test
    @DisplayName("updateEntityFromDTO avec request null retourne sans exception (L75)")
    void updateEntityFromDTO_requestNull_returnsWithoutException() {
        DemandeAide entity = new DemandeAide();
        entity.setTitre("Original");
        // No exception should be thrown
        mapper.updateEntityFromDTO(entity, null);
        assertThat(entity.getTitre()).isEqualTo("Original"); // unchanged
    }

    @Test
    @DisplayName("updateEntityFromDTO avec description, typeAide, statut, dateSoumission non null met à jour (L81,L84,L87,L96)")
    void updateEntityFromDTO_allNonNullFields_updatesAll() {
        DemandeAide entity = new DemandeAide();
        entity.setTitre("Titre original");
        entity.setDescription("Description originale");
        entity.setTypeAide(TypeAide.AIDE_ALIMENTAIRE);
        entity.setStatut(StatutAide.EN_ATTENTE);

        LocalDateTime dateSoumission = LocalDateTime.now().minusDays(1);
        UpdateDemandeAideRequest request = UpdateDemandeAideRequest.builder()
                .titre("Nouveau titre")
                .description("Nouvelle description")
                .typeAide(TypeAide.TRANSPORT)
                .statut(StatutAide.EN_COURS_EVALUATION)
                .priorite(PrioriteAide.URGENTE)
                .dateSoumission(dateSoumission)
                .montantDemande(new BigDecimal("5000"))
                .build();

        mapper.updateEntityFromDTO(entity, request);

        assertThat(entity.getTitre()).isEqualTo("Nouveau titre");
        assertThat(entity.getDescription()).isEqualTo("Nouvelle description");
        assertThat(entity.getTypeAide()).isEqualTo(TypeAide.TRANSPORT);
        assertThat(entity.getStatut()).isEqualTo(StatutAide.EN_COURS_EVALUATION);
        assertThat(entity.getUrgence()).isTrue(); // URGENTE.isUrgente() = true
        assertThat(entity.getDateDemande()).isEqualTo(dateSoumission);
        assertThat(entity.getMontantDemande()).isEqualByComparingTo(new BigDecimal("5000"));
    }

    @Test
    @DisplayName("updateEntityFromDTO avec priorite null → urgence = false (L95 false branch)")
    void updateEntityFromDTO_prioriteNull_urgenceFalse() {
        DemandeAide entity = new DemandeAide();
        entity.setUrgence(true); // Start as urgent

        UpdateDemandeAideRequest request = UpdateDemandeAideRequest.builder()
                .priorite(null) // null → urgence = false (null && ... = false)
                .build();

        mapper.updateEntityFromDTO(entity, request);

        assertThat(entity.getUrgence()).isFalse();
    }

    @Test
    @DisplayName("updateEntityFromDTO avec priorite=NORMALE → urgence = false (L95 isUrgente()=false branch)")
    void updateEntityFromDTO_prioriteNormale_urgenceFalse() {
        DemandeAide entity = new DemandeAide();
        entity.setUrgence(true); // Start as urgent

        UpdateDemandeAideRequest request = UpdateDemandeAideRequest.builder()
                .priorite(PrioriteAide.NORMALE) // non-null but isUrgente() = false → urgence = false
                .build();

        mapper.updateEntityFromDTO(entity, request);

        assertThat(entity.getUrgence()).isFalse();
    }

    // ================================================================
    // toEntity
    // ================================================================

    @Test
    @DisplayName("toEntity avec request null retourne null (L111)")
    void toEntity_requestNull_returnsNull() {
        DemandeAide entity = mapper.toEntity(null, null, null, null);
        assertThat(entity).isNull();
    }

    @Test
    @DisplayName("toEntity avec request valide crée une entité correcte")
    void toEntity_requestValide_creeEntite() {
        CreateDemandeAideRequest request = CreateDemandeAideRequest.builder()
                .titre("Aide test")
                .description("Description")
                .typeAide(TypeAide.AIDE_ALIMENTAIRE)
                .priorite(PrioriteAide.URGENTE)
                .montantDemande(new BigDecimal("1000"))
                .membreDemandeurId(UUID.randomUUID())
                .associationId(UUID.randomUUID())
                .build();

        DemandeAide entity = mapper.toEntity(request, null, null, null);

        assertThat(entity).isNotNull();
        assertThat(entity.getTitre()).isEqualTo("Aide test");
        assertThat(entity.getTypeAide()).isEqualTo(TypeAide.AIDE_ALIMENTAIRE);
        assertThat(entity.getUrgence()).isTrue(); // URGENTE.isUrgente() = true
        assertThat(entity.getStatut()).isEqualTo(StatutAide.EN_ATTENTE);
    }

    @Test
    @DisplayName("toEntity avec priorite null → urgence = false (L121 false branch)")
    void toEntity_prioriteNull_urgenceFalse() {
        CreateDemandeAideRequest request = CreateDemandeAideRequest.builder()
                .titre("Aide priorite null")
                .description("Desc")
                .typeAide(TypeAide.TRANSPORT)
                .priorite(null) // null → urgence = false
                .membreDemandeurId(UUID.randomUUID())
                .associationId(UUID.randomUUID())
                .build();

        DemandeAide entity = mapper.toEntity(request, null, null, null);

        assertThat(entity).isNotNull();
        assertThat(entity.getUrgence()).isFalse();
    }
}
