package com.ruoyi.app.omgpay;

import com.ruoyi.app.omgpay.dto.OmgPaymentErrorResponse;
import com.ruoyi.app.omgpay.dto.OmgRefundPaymentRequest;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.utils.MessageUtils;
import com.ruoyi.system.omgpay.service.OmgIpnAuditService;
import org.junit.jupiter.api.Test;
import org.mockito.MockedStatic;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;

import java.lang.reflect.Method;
import java.util.Map;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.*;

class OmgPaymentRefundControllerTest {
    @Test
    void exposesAuthenticatedOrderIdOnlyRefundContract() throws Exception {
        Method method = OmgPaymentController.class.getDeclaredMethod(
                "refund", String.class, OmgRefundPaymentRequest.class);

        assertArrayEquals(new String[]{"/refund"}, method.getAnnotation(PostMapping.class).value());
        assertEquals("token", method.getParameters()[0].getAnnotation(RequestHeader.class).name());
        assertNotNull(method.getParameters()[1].getAnnotation(RequestBody.class));
        assertEquals(1, OmgRefundPaymentRequest.class.getDeclaredFields().length);
        assertEquals("orderId", OmgRefundPaymentRequest.class.getDeclaredFields()[0].getName());
        assertTrue(java.util.Arrays.stream(method.getParameterTypes())
                .noneMatch(Map.class::isAssignableFrom));
    }

    @Test
    void returnsStableLocalizedTestEnvironmentRejection() {
        try (MockedStatic<MessageUtils> messages = mockStatic(MessageUtils.class)) {
            messages.when(() -> MessageUtils.message(anyString())).thenAnswer(call -> call.getArgument(0));
            OmgPaymentTokenUserResolver resolver = mock(OmgPaymentTokenUserResolver.class);
            OmgPaymentRefundService refundService = mock(OmgPaymentRefundService.class);
            when(resolver.requireUserId("token")).thenReturn(5L);
            when(refundService.refund(5L, "DD-1")).thenThrow(new OmgPaymentBusinessException(
                    OmgPaymentErrorCode.PAYMENT_REFUND_UNAVAILABLE_IN_TEST_ENVIRONMENT));
            OmgRefundPaymentRequest request = new OmgRefundPaymentRequest();
            request.setOrderId("DD-1");

            AjaxResult result = controller(resolver, refundService).refund("token", request);

            assertEquals("omg.pay.refund.unavailable.test.environment", result.get("msg"));
            assertEquals("PAYMENT_REFUND_UNAVAILABLE_IN_TEST_ENVIRONMENT",
                    ((OmgPaymentErrorResponse) result.get("data")).status());
        }
    }

    @Test
    void unexpectedFailureUsesStableRefundFailureWithoutLeakingToken() {
        try (MockedStatic<MessageUtils> messages = mockStatic(MessageUtils.class)) {
            messages.when(() -> MessageUtils.message(anyString())).thenAnswer(call -> call.getArgument(0));
            OmgPaymentTokenUserResolver resolver = mock(OmgPaymentTokenUserResolver.class);
            OmgPaymentRefundService refundService = mock(OmgPaymentRefundService.class);
            when(resolver.requireUserId("NEVER_LOG")).thenReturn(5L);
            when(refundService.refund(5L, "DD-1")).thenThrow(new IllegalStateException("unexpected"));
            OmgRefundPaymentRequest request = new OmgRefundPaymentRequest();
            request.setOrderId("DD-1");

            AjaxResult result = controller(resolver, refundService).refund("NEVER_LOG", request);

            assertEquals("PAYMENT_REFUND_FAILED",
                    ((OmgPaymentErrorResponse) result.get("data")).status());
        }
    }

    private static OmgPaymentController controller(OmgPaymentTokenUserResolver resolver,
                                                   OmgPaymentRefundService refundService) {
        return new OmgPaymentController(resolver, mock(OmgPaymentCreateService.class),
                mock(OmgPaymentNotifyService.class), mock(OmgIpnAuditService.class),
                mock(OmgPaymentQueryService.class), mock(OmgPaymentRetryService.class), refundService);
    }
}
