package com.ruoyi.web.modules.order.service;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
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 java.util.Collections;
import java.util.Date;
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.cart.facade.ICartFacade;
import com.ruoyi.web.modules.goods.mapper.BizGoodsMapper;
import com.ruoyi.web.modules.order.constant.OrderConstants;
import com.ruoyi.web.modules.order.domain.BizOrder;
import com.ruoyi.web.modules.order.domain.BizOrderItem;
import com.ruoyi.web.modules.order.mapper.BizOrderItemMapper;
import com.ruoyi.web.modules.order.mapper.BizOrderMapper;
import com.ruoyi.web.modules.order.service.impl.OrderPaySuccessServiceImpl;
import com.ruoyi.web.modules.order.support.CheckoutSupport;
import com.ruoyi.web.modules.pay.domain.BizPayRecord;
import com.ruoyi.web.modules.pay.mapper.BizPayRecordMapper;
import com.ruoyi.web.modules.stock.service.IStockOutboundFacade;
import com.ruoyi.web.modules.goods.domain.BizGoods;

@ExtendWith(MockitoExtension.class)
class OrderPaySuccessServiceImplTest
{
    @Mock
    private BizOrderMapper orderMapper;

    @Mock
    private BizOrderItemMapper orderItemMapper;

    @Mock
    private BizGoodsMapper goodsMapper;

    @Mock
    private ICartFacade cartFacade;

    @Mock
    private CheckoutSupport checkoutSupport;

    @Mock
    private BizPayRecordMapper payRecordMapper;

    @Mock
    private IStockOutboundFacade stockOutboundFacade;

    @InjectMocks
    private OrderPaySuccessServiceImpl orderPaySuccessService;

    @Test
    void completeWeChatPay_removesCartItems()
    {
        BizPayRecord record = new BizPayRecord();
        record.setPayId(1L);
        record.setOrderId(900L);
        record.setPayStatus("0");
        when(payRecordMapper.selectByOutTradeNo("O20260526000001")).thenReturn(record);
        BizOrder order = pendingOrder();
        when(orderMapper.selectById(900L)).thenReturn(order);
        BizOrderItem item = new BizOrderItem();
        item.setGoodsId(1L);
        item.setQuantity(2);
        item.setCartItemId(10L);
        when(orderItemMapper.selectByOrderId(900L)).thenReturn(Collections.singletonList(item));
        BizGoods goods = new BizGoods();
        goods.setGoodsId(1L);
        goods.setStock(20);
        when(goodsMapper.selectById(1L)).thenReturn(goods);
        when(goodsMapper.deductStock(1L, 2)).thenReturn(1);
        when(orderMapper.updateForPay(any(BizOrder.class))).thenReturn(1);

        orderPaySuccessService.completeWeChatPay("O20260526000001", "WX123", new Date());

        verify(cartFacade).removeItems(200L, Collections.singletonList(10L));
        verify(payRecordMapper).updateForSuccess(eq(1L), eq("WX123"), any(Date.class));
        verify(stockOutboundFacade).createOrderDeductOutbound(any());
    }

    @Test
    void completeWeChatPay_idempotentWhenAlreadyPaid()
    {
        BizPayRecord record = new BizPayRecord();
        record.setPayId(1L);
        record.setOrderId(900L);
        record.setPayStatus("1");
        when(payRecordMapper.selectByOutTradeNo("O20260526000001")).thenReturn(record);

        orderPaySuccessService.completeWeChatPay("O20260526000001", "WX123", new Date());

        verify(orderMapper, never()).updateForPay(any());
    }

    @Test
    void completeWeChatPay_stockFailed()
    {
        BizPayRecord record = new BizPayRecord();
        record.setPayId(1L);
        record.setOrderId(900L);
        record.setPayStatus("0");
        when(payRecordMapper.selectByOutTradeNo("O20260526000001")).thenReturn(record);
        when(orderMapper.selectById(900L)).thenReturn(pendingOrder());
        BizOrderItem item = new BizOrderItem();
        item.setGoodsId(1L);
        item.setQuantity(2);
        when(orderItemMapper.selectByOrderId(900L)).thenReturn(Collections.singletonList(item));
        when(goodsMapper.selectById(1L)).thenReturn(new BizGoods());
        when(goodsMapper.deductStock(1L, 2)).thenReturn(0);

        ServiceException ex = assertThrows(ServiceException.class,
                () -> orderPaySuccessService.completeWeChatPay("O20260526000001", "WX123", new Date()));
        assertEquals(OrderConstants.MSG_STOCK_DEDUCT_FAILED, ex.getMessage());
    }

    private BizOrder pendingOrder()
    {
        BizOrder order = new BizOrder();
        order.setOrderId(900L);
        order.setShopId(10L);
        order.setMemberId(200L);
        order.setOrderStatus(OrderConstants.STATUS_PENDING_PAY);
        order.setPayAmount(new BigDecimal("25.00"));
        order.setOrderNo("O20260526000001");
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.HOUR, 1);
        order.setPayExpireTime(calendar.getTime());
        return order;
    }
}
