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

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
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.Arrays;
import java.util.Collections;
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.account.facade.IMemberFacade;
import com.ruoyi.web.modules.order.constant.OrderAppConstants;
import com.ruoyi.web.modules.order.constant.OrderConstants;
import com.ruoyi.web.modules.order.domain.BizOrder;
import com.ruoyi.web.modules.order.domain.BizOrderAftersale;
import com.ruoyi.web.modules.order.domain.BizOrderItem;
import com.ruoyi.web.modules.order.dto.OrderAftersaleSubmitDTO;
import com.ruoyi.web.modules.order.mapper.BizOrderAftersaleMapper;
import com.ruoyi.web.modules.order.mapper.BizOrderItemMapper;
import com.ruoyi.web.modules.order.mapper.BizOrderMapper;
import com.ruoyi.web.modules.order.service.impl.OrderAftersaleAppServiceImpl;
import com.ruoyi.web.modules.order.support.OrderAppSupport;
import com.ruoyi.web.modules.order.vo.OrderAftersaleSubmitResultVO;

@ExtendWith(MockitoExtension.class)
class OrderAftersaleAppServiceImplTest
{
    private static final Long MEMBER_ID = 200L;

    private static final Long ORDER_ID = 900L;

    private static final Long ITEM_ID = 100L;

    @Mock
    private IMemberFacade memberFacade;

    @Mock
    private BizOrderMapper orderMapper;

    @Mock
    private BizOrderItemMapper orderItemMapper;

    @Mock
    private BizOrderAftersaleMapper aftersaleMapper;

    @Mock
    private OrderAppSupport orderAppSupport;

    @InjectMocks
    private OrderAftersaleAppServiceImpl aftersaleAppService;

    @Test
    void submit_wholeOrder_success()
    {
        when(memberFacade.isMemberEnabled(MEMBER_ID)).thenReturn(true);
        BizOrder order = new BizOrder();
        order.setOrderId(ORDER_ID);
        order.setOrderStatus(OrderConstants.STATUS_PENDING_SHIP);
        order.setPayAmount(new BigDecimal("88.00"));
        order.setShopId(10L);
        order.setOrderNo("O20260526000001");
        when(orderMapper.selectByIdAndMember(ORDER_ID, MEMBER_ID)).thenReturn(order);
        when(orderItemMapper.selectByOrderId(ORDER_ID)).thenReturn(Collections.singletonList(orderItem(ITEM_ID, 2)));
        when(aftersaleMapper.countInProgressByOrderId(ORDER_ID)).thenReturn(0);
        when(orderAppSupport.nextAftersaleNo()).thenReturn("AS20260526000001");
        when(aftersaleMapper.insert(any(BizOrderAftersale.class))).thenAnswer(inv -> {
            BizOrderAftersale row = inv.getArgument(0);
            assertNull(row.getOrderItemId());
            return 1;
        });

        OrderAftersaleSubmitDTO dto = new OrderAftersaleSubmitDTO();
        dto.setOrderId(ORDER_ID);
        dto.setApplyType(OrderAppConstants.AFTERSALE_TYPE_REFUND_UNSHIPPED);
        dto.setApplyReason("不想要了");
        dto.setApplyAmount(new BigDecimal("88.00"));

        OrderAftersaleSubmitResultVO result = aftersaleAppService.submit(MEMBER_ID, dto);

        assertEquals("AS20260526000001", result.getAftersaleNo());
        verify(aftersaleMapper).insert(any());
    }

    @Test
    void submit_inProgress_throws()
    {
        when(memberFacade.isMemberEnabled(MEMBER_ID)).thenReturn(true);
        BizOrder order = new BizOrder();
        order.setOrderId(ORDER_ID);
        order.setOrderStatus(OrderConstants.STATUS_PENDING_SHIP);
        order.setPayAmount(new BigDecimal("88.00"));
        when(orderMapper.selectByIdAndMember(ORDER_ID, MEMBER_ID)).thenReturn(order);
        when(orderItemMapper.selectByOrderId(ORDER_ID)).thenReturn(Collections.singletonList(orderItem(ITEM_ID, 1)));
        when(aftersaleMapper.countInProgressByOrderId(ORDER_ID)).thenReturn(1);

        OrderAftersaleSubmitDTO dto = new OrderAftersaleSubmitDTO();
        dto.setOrderId(ORDER_ID);
        dto.setApplyType(OrderAppConstants.AFTERSALE_TYPE_REFUND_UNSHIPPED);
        dto.setApplyReason("不想要了");
        dto.setApplyAmount(new BigDecimal("88.00"));

        ServiceException ex = assertThrows(ServiceException.class, () -> aftersaleAppService.submit(MEMBER_ID, dto));
        assertEquals(OrderAppConstants.MSG_AFTERSALE_IN_PROGRESS, ex.getMessage());
        verify(aftersaleMapper, never()).insert(any());
    }

    @Test
    void submit_returnRefund_setsTotalQuantity()
    {
        when(memberFacade.isMemberEnabled(MEMBER_ID)).thenReturn(true);
        BizOrder order = new BizOrder();
        order.setOrderId(ORDER_ID);
        order.setOrderStatus(OrderConstants.STATUS_SHIPPED);
        order.setPayAmount(new BigDecimal("120.00"));
        order.setShopId(10L);
        order.setOrderNo("O20260526000001");
        when(orderMapper.selectByIdAndMember(ORDER_ID, MEMBER_ID)).thenReturn(order);
        when(orderItemMapper.selectByOrderId(ORDER_ID)).thenReturn(Arrays.asList(orderItem(ITEM_ID, 2), orderItem(101L, 3)));
        when(aftersaleMapper.countInProgressByOrderId(ORDER_ID)).thenReturn(0);
        when(orderAppSupport.nextAftersaleNo()).thenReturn("AS20260526000002");
        when(aftersaleMapper.insert(any(BizOrderAftersale.class))).thenAnswer(inv -> {
            BizOrderAftersale row = inv.getArgument(0);
            assertEquals(Integer.valueOf(5), row.getReturnQuantity());
            assertEquals("商品A等2件商品", row.getGoodsName());
            return 1;
        });

        OrderAftersaleSubmitDTO dto = new OrderAftersaleSubmitDTO();
        dto.setOrderId(ORDER_ID);
        dto.setApplyType(OrderAppConstants.AFTERSALE_TYPE_RETURN_REFUND);
        dto.setApplyReason("不想要了");
        dto.setApplyAmount(new BigDecimal("120.00"));

        aftersaleAppService.submit(MEMBER_ID, dto);

        verify(aftersaleMapper).insert(any());
    }

    private static BizOrderItem orderItem(Long itemId, int quantity)
    {
        BizOrderItem item = new BizOrderItem();
        item.setItemId(itemId);
        item.setGoodsId(1L);
        item.setGoodsName("商品A");
        item.setQuantity(quantity);
        return item;
    }
}
