package com.ruoyi.app.omgpay;

import com.ruoyi.app.omgpay.dto.OmgPaymentErrorResponse;
import com.ruoyi.app.omgpay.dto.OmgQueryPaymentRequest;
import com.ruoyi.app.omgpay.dto.OmgQueryPaymentResponse;
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 static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.*;

class OmgPaymentQueryControllerTest {
    @Test
    void exposesAuthenticatedOrderIdOnlyQueryContractAndMapsResult() throws Exception {
        Method method = OmgPaymentController.class.getDeclaredMethod(
                "query", String.class, OmgQueryPaymentRequest.class);
        assertArrayEquals(new String[]{"/query"}, method.getAnnotation(PostMapping.class).value());
        assertEquals("token", method.getParameters()[0].getAnnotation(RequestHeader.class).name());
        assertNotNull(method.getParameters()[1].getAnnotation(RequestBody.class));

        OmgPaymentTokenUserResolver resolver = mock(OmgPaymentTokenUserResolver.class);
        OmgPaymentQueryService queryService = mock(OmgPaymentQueryService.class);
        when(resolver.requireUserId("token")).thenReturn(5L);
        OmgQueryPaymentResponse response = new OmgQueryPaymentResponse(
                "PAID", "1", "OMG123", "GW123", 100,
                "2026/08/13 12:00:00", "2026/08/13 11:59:00",
                "Credit_CreditCard", "0", "0.00");
        when(queryService.query(5L, "DD-1")).thenReturn(response);
        OmgPaymentController controller = controller(resolver, queryService);
        OmgQueryPaymentRequest request = new OmgQueryPaymentRequest();
        request.setOrderId("DD-1");

        AjaxResult result;
        try (MockedStatic<MessageUtils> messages = mockStatic(MessageUtils.class)) {
            messages.when(() -> MessageUtils.message(anyString())).thenAnswer(call -> call.getArgument(0));
            result = controller.query("token", request);
        }

        assertSame(response, result.get("data"));
    }

    @Test
    void mapsQueryBusinessAndUnexpectedFailuresToStableStatus() {
        try (MockedStatic<MessageUtils> messages = mockStatic(MessageUtils.class)) {
            messages.when(() -> MessageUtils.message(anyString())).thenAnswer(call -> call.getArgument(0));
            OmgPaymentTokenUserResolver resolver = mock(OmgPaymentTokenUserResolver.class);
            OmgPaymentQueryService queryService = mock(OmgPaymentQueryService.class);
            when(resolver.requireUserId("token")).thenReturn(5L);
            when(queryService.query(5L, "DD-1")).thenThrow(
                    new OmgPaymentBusinessException(OmgPaymentErrorCode.PAYMENT_QUERY_NOT_AVAILABLE));
            OmgQueryPaymentRequest request = new OmgQueryPaymentRequest();
            request.setOrderId("DD-1");
            OmgPaymentController controller = controller(resolver, queryService);

            AjaxResult business = controller.query("token", request);
            assertEquals("PAYMENT_QUERY_NOT_AVAILABLE",
                    ((OmgPaymentErrorResponse) business.get("data")).status());

            doThrow(new IllegalStateException("gateway down"))
                    .when(queryService).query(5L, "DD-1");
            AjaxResult unexpected = controller.query("token", request);
            assertEquals("PAYMENT_QUERY_FAILED",
                    ((OmgPaymentErrorResponse) unexpected.get("data")).status());
        }
    }

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