package dev.lions.unionflow.server.service;

import dev.lions.unionflow.server.api.dto.favoris.request.CreateFavoriRequest;
import dev.lions.unionflow.server.api.dto.favoris.response.FavoriResponse;
import io.quarkus.test.junit.QuarkusTest;
import io.quarkus.test.TestTransaction;
import jakarta.inject.Inject;
import jakarta.ws.rs.NotFoundException;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import java.util.List;
import java.util.Map;
import java.util.UUID;

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

@QuarkusTest
class FavorisServiceTest {

    @Inject
    FavorisService favorisService;

    @Test
    @TestTransaction
    @DisplayName("listerFavoris retourne une liste")
    void listerFavoris_returnsList() {
        List<FavoriResponse> list = favorisService.listerFavoris(UUID.randomUUID());
        assertThat(list).isNotNull();
    }

    @Test
    @TestTransaction
    @DisplayName("obtenirStatistiques retourne les clés attendues")
    void obtenirStatistiques_returnsMap() {
        Map<String, Object> stats = favorisService.obtenirStatistiques(UUID.randomUUID());
        assertThat(stats).containsKeys("totalFavoris", "totalPages", "totalDocuments", "totalContacts");
    }

    @Test
    @TestTransaction
    @DisplayName("creerFavori crée un favori et retourne un DTO")
    void creerFavori_createsAndReturnsDto() {
        UUID userId = UUID.randomUUID();
        CreateFavoriRequest request = CreateFavoriRequest.builder()
                .utilisateurId(userId)
                .typeFavori("PAGE")
                .titre("Favori test")
                .url("/test-url")
                .build();
        FavoriResponse response = favorisService.creerFavori(request);
        assertThat(response).isNotNull();
        assertThat(response.getId()).isNotNull();
        assertThat(response.getUtilisateurId()).isEqualTo(userId);
        assertThat(response.getTitre()).isEqualTo("Favori test");
    }

    @Test
    @TestTransaction
    @DisplayName("supprimerFavori : UUID inexistant lève NotFoundException")
    void supprimerFavori_inexistant_throwsNotFoundException() {
        UUID id = UUID.randomUUID();
        assertThatThrownBy(() -> favorisService.supprimerFavori(id))
                .isInstanceOf(NotFoundException.class)
                .hasMessageContaining(id.toString());
    }

    @Test
    @TestTransaction
    @DisplayName("creerFavori avec derniereVisite invalide ne lève pas d'exception (catch block)")
    void creerFavori_invalidDerniereVisite_doesNotThrow() {
        UUID userId = UUID.randomUUID();
        CreateFavoriRequest request = CreateFavoriRequest.builder()
                .utilisateurId(userId)
                .typeFavori("PAGE")
                .titre("Favori date invalide")
                .url("/test-url")
                .derniereVisite("NOT_A_VALID_DATE")
                .build();
        // La date invalide est ignorée (catch silencieux) → pas d'exception
        FavoriResponse response = favorisService.creerFavori(request);
        assertThat(response).isNotNull();
        assertThat(response.getId()).isNotNull();
    }

    // ================================================================
    // supprimerFavori — branche success (deleted=true)
    // ================================================================

    @Test
    @TestTransaction
    @DisplayName("supprimerFavori : UUID existant supprime le favori avec succès")
    void supprimerFavori_existant_supprime() {
        UUID userId = UUID.randomUUID();
        CreateFavoriRequest request = CreateFavoriRequest.builder()
                .utilisateurId(userId)
                .typeFavori("DOCUMENT")
                .titre("Favori à supprimer")
                .url("/doc-url")
                .build();
        FavoriResponse created = favorisService.creerFavori(request);

        // Ne doit pas lancer d'exception
        favorisService.supprimerFavori(created.getId());

        // Vérifier que la liste est vide pour cet utilisateur (le favori est supprimé)
        List<FavoriResponse> restants = favorisService.listerFavoris(userId);
        assertThat(restants).noneMatch(f -> f.getId().equals(created.getId()));
    }

    // ================================================================
    // toDTO — branche derniereVisite non-null (ligne 90)
    // ================================================================

    @Test
    @TestTransaction
    @DisplayName("creerFavori avec derniereVisite valide retourne la date en string dans le DTO")
    void creerFavori_validDerniereVisite_returnsDerniereVisiteString() {
        UUID userId = UUID.randomUUID();
        String dateValide = "2025-06-15T10:30:00";
        CreateFavoriRequest request = CreateFavoriRequest.builder()
                .utilisateurId(userId)
                .typeFavori("CONTACT")
                .titre("Favori date valide")
                .url("/contact-url")
                .derniereVisite(dateValide)
                .build();

        FavoriResponse response = favorisService.creerFavori(request);

        assertThat(response).isNotNull();
        // La date a été parsée et stockée, le toDTO la re-sérialise en String non-null
        assertThat(response.getDerniereVisite()).isNotNull();
    }

    // ================================================================
    // toEntity — branche dto null (ligne 96-97)
    // ================================================================

    @Test
    @DisplayName("toEntity avec dto null retourne null (via réflexion)")
    void toEntity_nullDto_returnsNull() throws Exception {
        java.lang.reflect.Method toEntity = dev.lions.unionflow.server.service.FavorisService.class
                .getDeclaredMethod("toEntity", dev.lions.unionflow.server.api.dto.favoris.request.CreateFavoriRequest.class);
        toEntity.setAccessible(true);
        Object result = toEntity.invoke(favorisService, (Object) null);
        assertThat(result).isNull();
    }

    // ================================================================
    // toDTO — branche favori null (ligne 76-77)
    // ================================================================

    @Test
    @DisplayName("toDTO avec favori null retourne null (via réflexion)")
    void toDTO_nullFavori_returnsNull() throws Exception {
        java.lang.reflect.Method toDTO = dev.lions.unionflow.server.service.FavorisService.class
                .getDeclaredMethod("toDTO", dev.lions.unionflow.server.entity.Favori.class);
        toDTO.setAccessible(true);
        Object result = toDTO.invoke(favorisService, (Object) null);
        assertThat(result).isNull();
    }

    // ================================================================
    // toEntity — branche derniereVisite null (ligne 109: dto.derniereVisite() != null → false)
    // Couvert par creerFavori sans derniereVisite, mais on le documente explicitement
    // ================================================================

    @Test
    @TestTransaction
    @DisplayName("creerFavori sans derniereVisite (null) crée le favori sans date de visite")
    void creerFavori_nullDerniereVisite_noParsing() {
        UUID userId = UUID.randomUUID();
        CreateFavoriRequest request = CreateFavoriRequest.builder()
                .utilisateurId(userId)
                .typeFavori("RACCOURCI")
                .titre("Favori sans date")
                .url("/raccourci-url")
                .derniereVisite(null)
                .build();

        FavoriResponse response = favorisService.creerFavori(request);

        assertThat(response).isNotNull();
        assertThat(response.getDerniereVisite()).isNull();
    }
}
