package dev.lions.unionflow.server.resource;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;

import dev.lions.unionflow.server.repository.IntentionPaiementRepository;
import dev.lions.unionflow.server.service.mutuelle.epargne.TransactionEpargneService;
import jakarta.ws.rs.core.Response;
import java.lang.reflect.Field;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.junit.jupiter.MockitoExtension;

/**
 * Tests unitaires purs (sans Quarkus) pour {@link WaveRedirectResource#mockComplete}.
 *
 * <p>Instancie directement {@link WaveRedirectResource} avec {@code mockEnabled=false}
 * via réflexion pour tester la branche {@code if (!mockEnabled)} de façon déterministe,
 * indépendamment des profils Quarkus.
 */
@ExtendWith(MockitoExtension.class)
@DisplayName("WaveRedirectResource.mockComplete — branche mockEnabled=false")
class WaveRedirectResourceMockDisabledUnitTest {

    private WaveRedirectResource resource;

    @BeforeEach
    void setUp() throws Exception {
        resource = new WaveRedirectResource();

        // Injecter mockEnabled=false via réflexion (simule wave.mock.enabled=false)
        setField(resource, "mockEnabled", false);
        // Injecter deepLinkScheme via réflexion (simule wave.deep.link.scheme=unionflow)
        setField(resource, "deepLinkScheme", "unionflow");
        // Injecter les dépendances mockées (non utilisées dans le chemin !mockEnabled, mais requis)
        setField(resource, "intentionPaiementRepository", mock(IntentionPaiementRepository.class));
        setField(resource, "transactionEpargneService", mock(TransactionEpargneService.class));
    }

    // =========================================================================
    // Branche !mockEnabled (L82-83)
    // =========================================================================

    /**
     * Couvre L82 (LOG.warn) et L83 (return redirect vers error).
     *
     * <p>Quand {@code mockEnabled=false} et {@code ref} non-null : le if {@code !mockEnabled}
     * est vrai → L82 warn → L83 retourne un 303 vers le deep link "error".
     */
    @Test
    @DisplayName("mockComplete avec mockEnabled=false + ref valide → 303 vers deep link error (L82-83)")
    void mockComplete_mockDisabled_validRef_returns303ToErrorDeepLink() {
        String ref = "a1b2c3d4-e5f6-7890-abcd-ef1234567890";

        Response response = resource.mockComplete(ref);

        assertThat(response.getStatus()).isEqualTo(303);
        String location = response.getHeaderString("Location");
        assertThat(location).isNotNull();
        assertThat(location).contains("error");
        assertThat(location).startsWith("unionflow://");
    }

    /**
     * Couvre L82-83 avec ref=null : même branche {@code !mockEnabled}, le deep link
     * est construit sans ref (buildDeepLink("error", null) → pas de &ref=... dans l'URL).
     */
    @Test
    @DisplayName("mockComplete avec mockEnabled=false + ref null → 303 vers deep link error sans ref (L82-83)")
    void mockComplete_mockDisabled_nullRef_returns303ToErrorDeepLinkWithoutRef() {
        Response response = resource.mockComplete(null);

        assertThat(response.getStatus()).isEqualTo(303);
        String location = response.getHeaderString("Location");
        assertThat(location).isNotNull();
        assertThat(location).contains("error");
        assertThat(location).doesNotContain("&ref=");
    }

    /**
     * Couvre L82-83 avec ref blank : branche {@code !mockEnabled} toujours vraie.
     * {@code buildDeepLink("error", "   ")} inclut le ref blank dans l'URL
     * car {@code ref.isBlank()} n'est pas vérifié dans buildDeepLink.
     *
     * <p>Note: la condition {@code ref.isBlank()} à L85 n'est PAS vérifiée quand
     * mockEnabled=false car L85 est après le return à L83.
     */
    @Test
    @DisplayName("mockComplete avec mockEnabled=false + ref blank → 303 vers deep link error (L82-83, ref non vérifié)")
    void mockComplete_mockDisabled_blankRef_returns303() {
        Response response = resource.mockComplete("   ");

        assertThat(response.getStatus()).isEqualTo(303);
        String location = response.getHeaderString("Location");
        assertThat(location).isNotNull();
        assertThat(location).contains("error");
    }

    // =========================================================================
    // success() branche mockEnabled=false (L58-59)
    // =========================================================================

    /**
     * Quand mockEnabled=false, la condition `mockEnabled && ref != null && !ref.isBlank()`
     * est immédiatement false → branche false (mockEnabled=false) couverte pour success().
     */
    @Test
    @DisplayName("success avec mockEnabled=false + ref valide → 303 sans appel applyMockCompletion (branche mockEnabled=false)")
    void success_mockDisabled_validRef_returns303WithoutMock() {
        String ref = "a1b2c3d4-e5f6-7890-abcd-ef1234567890";

        Response response = resource.success(ref);

        assertThat(response.getStatus()).isEqualTo(303);
        String location = response.getHeaderString("Location");
        assertThat(location).isNotNull().contains("success").contains(ref);
    }

    // =========================================================================
    // Error cases / edge cases
    // =========================================================================

    /**
     * success() avec ref null et mockEnabled=false : la condition mockEnabled && ref != null
     * est fausse → branche false, retourne 303 sans appel de service.
     */
    @Test
    @DisplayName("success avec mockEnabled=false + ref null → 303 (branche mockEnabled false, ref null)")
    void success_mockDisabled_nullRef_returns303() {
        Response response = resource.success(null);

        assertThat(response.getStatus()).isEqualTo(303);
        String location = response.getHeaderString("Location");
        assertThat(location).isNotNull();
        assertThat(location).startsWith("unionflow://");
    }

    /**
     * success() avec ref blank et mockEnabled=false : la condition mockEnabled && ref != null
     * est fausse (mockEnabled=false) → retourne 303.
     */
    @Test
    @DisplayName("success avec mockEnabled=false + ref blank → 303 (branche mockEnabled false, ref blank)")
    void success_mockDisabled_blankRef_returns303() {
        Response response = resource.success("   ");

        assertThat(response.getStatus()).isEqualTo(303);
        String location = response.getHeaderString("Location");
        assertThat(location).isNotNull();
    }

    /**
     * mockComplete() avec un ref long (UUID complet) : vérifie que la construction du deep link
     * ne tronque pas le ref et inclut bien sa valeur complète.
     */
    @Test
    @DisplayName("mockComplete avec ref UUID complet → deep link contient le ref intégralement")
    void mockComplete_mockDisabled_fullUuidRef_deepLinkContainsRef() {
        String longRef = "12345678-1234-1234-1234-123456789012";
        Response response = resource.mockComplete(longRef);

        assertThat(response.getStatus()).isEqualTo(303);
        String location = response.getHeaderString("Location");
        assertThat(location).isNotNull().contains("error");
    }

    // =========================================================================
    // Helper
    // =========================================================================

    private void setField(Object target, String fieldName, Object value) throws Exception {
        Class<?> clazz = target.getClass();
        while (clazz != null) {
            try {
                Field field = clazz.getDeclaredField(fieldName);
                field.setAccessible(true);
                field.set(target, value);
                return;
            } catch (NoSuchFieldException e) {
                clazz = clazz.getSuperclass();
            }
        }
        throw new NoSuchFieldException("Field not found: " + fieldName + " in " + target.getClass());
    }
}
