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

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 OrangeMoneyPaymentProviderTest {

    private OrangeMoneyPaymentProvider provider;

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

    @Test
    void getProviderCode_returns_ORANGE_MONEY() {
        assertThat(provider.getProviderCode()).isEqualTo("ORANGE_MONEY");
    }

    @Test
    void code_constant_is_ORANGE_MONEY() {
        assertThat(OrangeMoneyPaymentProvider.CODE).isEqualTo("ORANGE_MONEY");
    }

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

        CheckoutSession session = provider.initiateCheckout(req);

        assertThat(session.externalId()).startsWith("OM-MOCK-");
        assertThat(session.checkoutUrl()).contains("mock.orange.ci");
        assertThat(session.expiresAt()).isNotNull();
        assertThat(session.providerMetadata()).containsEntry("mock", "true");
        assertThat(session.providerMetadata()).containsEntry("provider", "ORANGE_MONEY");
    }

    @Test
    void initiateCheckout_whenConfigured_throwsNotImplemented() throws Exception {
        Field f = OrangeMoneyPaymentProvider.class.getDeclaredField("clientId");
        f.setAccessible(true);
        f.set(provider, "real-client-id");

        CheckoutRequest req = new CheckoutRequest(
                BigDecimal.valueOf(1000), "XOF",
                "+2250700000001", "user@test.com",
                "OM-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("OM-EXT-123");
        assertThat(status).isEqualTo(PaymentStatus.PROCESSING);
    }

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

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

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

    @Test
    void isAvailable_whenClientIdSet_returnsTrue() throws Exception {
        Field f = OrangeMoneyPaymentProvider.class.getDeclaredField("clientId");
        f.setAccessible(true);
        f.set(provider, "real-client-id");
        assertThat(provider.isAvailable()).isTrue();
    }

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

    @Test
    void initiateCheckout_whenClientIdNull_returnsMockSession() throws Exception {
        Field f = OrangeMoneyPaymentProvider.class.getDeclaredField("clientId");
        f.setAccessible(true);
        f.set(provider, null);

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

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