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

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.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 MtnMomoPaymentProviderTest {

    private MtnMomoPaymentProvider provider;

    @BeforeEach
    void setUp() {
        provider = new MtnMomoPaymentProvider();
        // subscriptionKey defaults to "" — mock mode active
    }

    @Test
    void getProviderCode_returns_MTN_MOMO() {
        assertThat(provider.getProviderCode()).isEqualTo("MTN_MOMO");
    }

    @Test
    void code_constant_is_MTN_MOMO() {
        assertThat(MtnMomoPaymentProvider.CODE).isEqualTo("MTN_MOMO");
    }

    @Test
    void initiateCheckout_whenNotConfigured_returnsMockSession() throws Exception {
        CheckoutRequest req = new CheckoutRequest(
                BigDecimal.valueOf(5000), "XOF",
                "+2250100000000", "test@test.com",
                "REF-001", "http://success", "http://cancel", Map.of());

        CheckoutSession session = provider.initiateCheckout(req);

        assertThat(session.externalId()).startsWith("MTN-MOCK-");
        assertThat(session.checkoutUrl()).contains("mock.mtn.ci");
        assertThat(session.expiresAt()).isNotNull();
        assertThat(session.providerMetadata()).containsEntry("mock", "true");
        assertThat(session.providerMetadata()).containsEntry("provider", "MTN_MOMO");
    }

    @Test
    void initiateCheckout_whenConfigured_throwsNotImplemented() throws Exception {
        Field f = MtnMomoPaymentProvider.class.getDeclaredField("subscriptionKey");
        f.setAccessible(true);
        f.set(provider, "real-subscription-key");

        CheckoutRequest req = new CheckoutRequest(
                BigDecimal.valueOf(1000), "XOF",
                "+2250100000001", "user@test.com",
                "REF-002", "http://success", "http://cancel", Map.of());

        assertThatThrownBy(() -> provider.initiateCheckout(req))
                .isInstanceOf(PaymentException.class)
                .hasMessageContaining("501");
    }

    @Test
    void getStatus_returnsPROCESSING() throws Exception {
        PaymentStatus status = provider.getStatus("MTN-EXT-123");
        assertThat(status).isEqualTo(PaymentStatus.PROCESSING);
    }

    @Test
    void processWebhook_throwsNotImplemented() {
        assertThatThrownBy(() -> provider.processWebhook("{}", Map.of()))
                .isInstanceOf(PaymentException.class)
                .hasMessageContaining("501");
    }

    @Test
    void isAvailable_whenSubscriptionKeyEmpty_returnsFalse() {
        assertThat(provider.isAvailable()).isFalse();
    }

    @Test
    void isAvailable_whenSubscriptionKeyBlank_returnsFalse() throws Exception {
        Field f = MtnMomoPaymentProvider.class.getDeclaredField("subscriptionKey");
        f.setAccessible(true);
        f.set(provider, "   ");
        assertThat(provider.isAvailable()).isFalse();
    }

    @Test
    void isAvailable_whenSubscriptionKeySet_returnsTrue() throws Exception {
        Field f = MtnMomoPaymentProvider.class.getDeclaredField("subscriptionKey");
        f.setAccessible(true);
        f.set(provider, "real-key");
        assertThat(provider.isAvailable()).isTrue();
    }

    @Test
    void isAvailable_whenSubscriptionKeyNull_returnsFalse() throws Exception {
        Field f = MtnMomoPaymentProvider.class.getDeclaredField("subscriptionKey");
        f.setAccessible(true);
        f.set(provider, null);
        assertThat(provider.isAvailable()).isFalse();
    }

    @Test
    void initiateCheckout_whenSubscriptionKeyNull_returnsMockSession() throws Exception {
        Field f = MtnMomoPaymentProvider.class.getDeclaredField("subscriptionKey");
        f.setAccessible(true);
        f.set(provider, null);

        CheckoutRequest req = new CheckoutRequest(
                BigDecimal.valueOf(2000), "XOF",
                "+2250100000002", "null@test.com",
                "REF-NULL", "http://success", "http://cancel", Map.of());

        CheckoutSession session = provider.initiateCheckout(req);
        assertThat(session.externalId()).startsWith("MTN-MOCK-");
    }
}
