package com.ruoyi.web.modules.pay.service.impl;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.math.BigDecimal;
import java.util.Calendar;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.web.modules.order.domain.BizOrder;
import com.ruoyi.web.modules.order.service.IOrderPaySuccessService;
import com.ruoyi.web.modules.order.support.CheckoutSupport;
import com.ruoyi.web.modules.pay.config.WeChatPayProperties;
import com.ruoyi.web.modules.pay.constant.PayConstants;
import com.ruoyi.web.modules.pay.service.IShopWechatPayService;
import com.ruoyi.web.modules.pay.support.WeChatPaySupport;
import com.ruoyi.web.modules.pay.vo.WeChatPayParamsVO;

@ExtendWith(MockitoExtension.class)
class WeChatPayServiceImplTest
{
    @Mock
    private WeChatPayProperties payProperties;

    @Mock
    private WeChatPaySupport paySupport;

    @Mock
    private com.ruoyi.web.modules.pay.mapper.BizPayRecordMapper payRecordMapper;

    @Mock
    private IShopWechatPayService shopWechatPayService;

    @Mock
    private IOrderPaySuccessService orderPaySuccessService;

    @Mock
    private CheckoutSupport checkoutSupport;

    @InjectMocks
    private WeChatPayServiceImpl weChatPayService;

    private BizOrder order;

    @BeforeEach
    void setUp()
    {
        order = new BizOrder();
        order.setOrderId(900L);
        order.setOrderNo("O20260526000001");
        order.setShopId(101L);
        order.setPayAmount(new BigDecimal("25.00"));
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.HOUR, 1);
        order.setPayExpireTime(calendar.getTime());
    }

    @Test
    void createJsapiPay_mockModeWithoutOpenid_succeeds()
    {
        when(payProperties.isRealPayEnabled()).thenReturn(false);
        when(payRecordMapper.selectLatestByOrderId(order.getOrderId())).thenReturn(null);

        WeChatPayParamsVO vo = weChatPayService.createJsapiPay(200L, order, null);

        assertTrue(vo.isMock());
        assertEquals(order.getOrderId(), vo.getOrderId());
        verify(payRecordMapper).insert(any());
        verify(shopWechatPayService, never()).resolvePayMchId(any());
        verify(paySupport, never()).createJsapiPrepayId(any(), any(), any(), any(), any(), any());
    }

    @Test
    void createJsapiPay_realModeWithoutOpenid_rejected()
    {
        when(payProperties.isRealPayEnabled()).thenReturn(true);

        ServiceException ex = assertThrows(ServiceException.class,
                () -> weChatPayService.createJsapiPay(200L, order, null));
        assertEquals(PayConstants.MSG_OPENID_REQUIRED, ex.getMessage());
        verify(shopWechatPayService, never()).resolvePayMchId(any());
    }

    @Test
    void createJsapiPay_realModeWithOpenid_delegatesToWeChat()
    {
        when(payProperties.isRealPayEnabled()).thenReturn(true);
        when(shopWechatPayService.resolvePayMchId(101L)).thenReturn("1900000109");
        when(payProperties.getNotifyUrl()).thenReturn("https://example.com/notify");
        when(paySupport.createJsapiPrepayId(eq(order.getOrderNo()), any(), eq(order.getPayAmount()),
                eq("openid-test"), eq("1900000109"), eq("https://example.com/notify")))
                .thenReturn("prepay-id-test");
        when(paySupport.buildJsapiPayParams("prepay-id-test")).thenReturn(java.util.Collections.singletonMap("appId", "wx-test"));
        when(payRecordMapper.selectLatestByOrderId(order.getOrderId())).thenReturn(null);

        WeChatPayParamsVO vo = weChatPayService.createJsapiPay(200L, order, "openid-test");

        assertTrue(!vo.isMock());
        verify(paySupport).createJsapiPrepayId(eq(order.getOrderNo()), any(), eq(order.getPayAmount()),
                eq("openid-test"), eq("1900000109"), eq("https://example.com/notify"));
    }
}
