package dev.lions.unionflow.server.payment.pispi;

import dev.lions.unionflow.server.api.payment.CheckoutRequest;
import dev.lions.unionflow.server.api.payment.CheckoutSession;
import dev.lions.unionflow.server.api.payment.PaymentException;
import dev.lions.unionflow.server.api.payment.PaymentStatus;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.Map;

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

class PispiPaymentProviderTest {

    private PispiPaymentProvider provider;

    @BeforeEach
    void setUp() throws Exception {
        provider = new PispiPaymentProvider();
        setField("clientId", "");
        setField("institutionCode", "");
        setField("institutionBic", "");
        // pispiClient et mapper non injectés → null, mais isConfigured() retourne false donc non appelés
    }

    private void setField(String name, String value) throws Exception {
        Field f = PispiPaymentProvider.class.getDeclaredField(name);
        f.setAccessible(true);
        f.set(provider, value);
    }

    @Test
    @DisplayName("getProviderCode retourne PISPI")
    void getProviderCode_returnsPISPI() {
        assertThat(provider.getProviderCode()).isEqualTo("PISPI");
    }

    @Test
    @DisplayName("isAvailable retourne false si non configuré")
    void isAvailable_whenNotConfigured_returnsFalse() {
        assertThat(provider.isAvailable()).isFalse();
    }

    @Test
    @DisplayName("initiateCheckout retourne une session mock si non configuré")
    void initiateCheckout_whenNotConfigured_returnsMockSession() throws Exception {
        CheckoutRequest req = new CheckoutRequest(
                new BigDecimal("10000"), "XOF",
                "+2250700000001", "user@test.ci",
                "SOUSCRIPTION-001", "https://ok", "https://cancel",
                Map.of()
        );
        CheckoutSession session = provider.initiateCheckout(req);
        assertThat(session.externalId()).startsWith("PISPI-MOCK-");
        assertThat(session.checkoutUrl()).startsWith("https://mock.pispi.bceao.int/pay/");
        assertThat(session.providerMetadata()).containsEntry("mock", "true");
        assertThat(session.providerMetadata()).containsEntry("provider", "PISPI");
    }

    @Test
    @DisplayName("getStatus retourne PROCESSING si non configuré")
    void getStatus_whenNotConfigured_returnsProcessing() throws Exception {
        assertThat(provider.getStatus("ANY-ID")).isEqualTo(PaymentStatus.PROCESSING);
    }

    @Test
    @DisplayName("processWebhook lève PaymentException — déléguer à /api/pispi/webhook")
    void processWebhook_throwsPaymentException() {
        assertThatThrownBy(() -> provider.processWebhook("body", Map.of()))
                .isInstanceOf(PaymentException.class)
                .hasMessageContaining("pispi/webhook")
                .extracting(e -> ((PaymentException) e).getHttpStatus())
                .isEqualTo(400);
    }
}
