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

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
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 java.util.List;
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.category.facade.ICategoryFacade;
import com.ruoyi.web.modules.delivery.facade.IShopDeliveryFacade;
import com.ruoyi.web.modules.goods.constant.GoodsConstants;
import com.ruoyi.web.modules.goods.facade.IGoodsPurchaseFacade;
import com.ruoyi.web.modules.goods.mapper.BizGoodsAttrMapper;
import com.ruoyi.web.modules.goods.mapper.BizGoodsPicMapper;
import com.ruoyi.web.modules.goods.mapper.BizGoodsServiceSnapshotMapper;
import com.ruoyi.web.modules.goods.vo.GoodsPurchaseVO;
import com.ruoyi.web.modules.goods.vo.GoodsServiceSnapshotVO;
import com.ruoyi.web.modules.home.dto.GoodsDetailBaseDTO;
import com.ruoyi.web.modules.home.mapper.GoodsAppMapper;
import com.ruoyi.web.modules.home.service.impl.GoodsAppServiceImpl;
import com.ruoyi.web.modules.home.vo.GoodsDetailAppVO;
import com.ruoyi.web.modules.home.vo.GoodsReviewAppVO;
import com.ruoyi.web.modules.order.domain.BizGoodsReview;
import com.ruoyi.web.modules.order.mapper.BizGoodsReviewMapper;
import com.ruoyi.web.modules.mall.facade.IMallConfigFacade;
import com.ruoyi.web.modules.order.support.OrderAppSupport;

@ExtendWith(MockitoExtension.class)
class GoodsAppServiceImplTest
{
    @Mock
    private GoodsAppMapper goodsAppMapper;

    @Mock
    private BizGoodsPicMapper goodsPicMapper;

    @Mock
    private BizGoodsServiceSnapshotMapper snapshotMapper;

    @Mock
    private BizGoodsAttrMapper goodsAttrMapper;

    @Mock
    private ICategoryFacade categoryFacade;

    @Mock
    private IGoodsPurchaseFacade purchaseFacade;

    @Mock
    private IShopDeliveryFacade shopDeliveryFacade;

    @Mock
    private BizGoodsReviewMapper reviewMapper;

    @Mock
    private OrderAppSupport orderAppSupport;

    @Mock
    private IMallConfigFacade mallConfigFacade;

    @InjectMocks
    private GoodsAppServiceImpl goodsAppService;

    private void stubDisplayFlags()
    {
        when(mallConfigFacade.isShowSales()).thenReturn(true);
    }

    @Test
    void getDetail_mergesMainPicAndSubPics()
    {
        stubDisplayFlags();
        when(goodsAppMapper.selectDetailBase(1L)).thenReturn(sampleBase());
        when(goodsPicMapper.selectPicUrlsByGoodsId(1L)).thenReturn(Arrays.asList("/sub1.jpg", "/sub2.jpg"));
        when(categoryFacade.getCategoryPath(10L)).thenReturn("兽药 > 抗生素");
        when(snapshotMapper.selectVisibleByGoodsId(1L)).thenReturn(Collections.emptyList());
        when(goodsAttrMapper.selectByGoodsId(1L)).thenReturn(Collections.emptyList());
        GoodsPurchaseVO purchase = new GoodsPurchaseVO();
        purchase.setAllowed(true);
        when(purchaseFacade.canPurchase(1L)).thenReturn(purchase);
        when(shopDeliveryFacade.getShipCity(101L)).thenReturn(null);

        GoodsDetailAppVO vo = goodsAppService.getDetail(1L);

        assertEquals(Arrays.asList("/main.jpg", "/sub1.jpg", "/sub2.jpg"), vo.getPics());
        assertEquals("出售中", vo.getGoodsStatusLabel());
        assertEquals("兽药 > 抗生素", vo.getCategoryPath());
        assertTrue(vo.getPurchase().isAllowed());
    }

    @Test
    void getDetail_mainPicOnlyWhenNoSubPics()
    {
        stubDisplayFlags();
        when(goodsAppMapper.selectDetailBase(1L)).thenReturn(sampleBase());
        when(goodsPicMapper.selectPicUrlsByGoodsId(1L)).thenReturn(Collections.emptyList());
        when(snapshotMapper.selectVisibleByGoodsId(1L)).thenReturn(Collections.emptyList());
        when(goodsAttrMapper.selectByGoodsId(1L)).thenReturn(Collections.emptyList());
        when(categoryFacade.getCategoryPath(10L)).thenReturn("兽药 > 抗生素");
        GoodsPurchaseVO purchase = new GoodsPurchaseVO();
        purchase.setAllowed(false);
        purchase.setReason("库存不足");
        when(purchaseFacade.canPurchase(1L)).thenReturn(purchase);
        when(shopDeliveryFacade.getShipCity(101L)).thenReturn(null);

        GoodsDetailAppVO vo = goodsAppService.getDetail(1L);

        assertEquals(Collections.singletonList("/main.jpg"), vo.getPics());
        assertFalse(vo.getPurchase().isAllowed());
    }

    @Test
    void getDetail_notFoundThrows()
    {
        when(goodsAppMapper.selectDetailBase(99L)).thenReturn(null);

        ServiceException ex = assertThrows(ServiceException.class, () -> goodsAppService.getDetail(99L));
        assertEquals(GoodsConstants.MSG_GOODS_NOT_FOUND, ex.getMessage());
    }

    @Test
    void getDetail_resolvesShipPromiseFromServices()
    {
        when(goodsAppMapper.selectDetailBase(1L)).thenReturn(sampleBase());
        when(goodsPicMapper.selectPicUrlsByGoodsId(1L)).thenReturn(Collections.emptyList());
        when(categoryFacade.getCategoryPath(10L)).thenReturn("兽药 > 抗生素");
        when(goodsAttrMapper.selectByGoodsId(1L)).thenReturn(Collections.emptyList());
        GoodsServiceSnapshotVO service = new GoodsServiceSnapshotVO();
        service.setServiceName("24小时发货");
        when(snapshotMapper.selectVisibleByGoodsId(1L)).thenReturn(Collections.singletonList(service));
        when(purchaseFacade.canPurchase(1L)).thenReturn(new GoodsPurchaseVO());
        when(shopDeliveryFacade.getShipCity(101L)).thenReturn("拉萨市");

        GoodsDetailAppVO vo = goodsAppService.getDetail(1L);

        assertEquals("24小时发货", vo.getLogistics().getShipPromise());
        assertEquals("拉萨市", vo.getLogistics().getShipCity());
        assertNull(vo.getLogistics().getFreightDesc());
    }

    @Test
    void getDetail_shopAndAfterSalePhone()
    {
        when(goodsAppMapper.selectDetailBase(1L)).thenReturn(sampleBase());
        when(goodsPicMapper.selectPicUrlsByGoodsId(1L)).thenReturn(Collections.emptyList());
        when(categoryFacade.getCategoryPath(10L)).thenReturn("兽药 > 抗生素");
        when(snapshotMapper.selectVisibleByGoodsId(1L)).thenReturn(Collections.emptyList());
        when(goodsAttrMapper.selectByGoodsId(1L)).thenReturn(Collections.emptyList());
        when(purchaseFacade.canPurchase(1L)).thenReturn(new GoodsPurchaseVO());
        when(shopDeliveryFacade.getShipCity(101L)).thenReturn(null);

        GoodsDetailAppVO vo = goodsAppService.getDetail(1L);

        assertNotNull(vo.getShop());
        assertEquals(101L, vo.getShop().getShopId());
        assertEquals("测试店铺", vo.getShop().getShopName());
        assertEquals("13800000000", vo.getAfterSalePhone());
    }

    @Test
    void canPurchase_delegatesFacade()
    {
        GoodsPurchaseVO purchase = new GoodsPurchaseVO();
        purchase.setAllowed(true);
        when(purchaseFacade.canPurchase(1L)).thenReturn(purchase);

        GoodsPurchaseVO result = goodsAppService.canPurchase(1L);

        verify(purchaseFacade).canPurchase(1L);
        assertTrue(result.isAllowed());
    }

    @Test
    void listReviews_mapsVisibleRows()
    {
        BizGoodsReview review = new BizGoodsReview();
        review.setReviewId(1L);
        review.setMemberNickName("张三");
        review.setContent("很好");
        review.setReviewPics("/a.jpg,/b.jpg");
        review.setScore(5);
        when(reviewMapper.selectByGoodsId(1L)).thenReturn(Collections.singletonList(review));
        when(orderAppSupport.splitPics("/a.jpg,/b.jpg")).thenReturn(Arrays.asList("/a.jpg", "/b.jpg"));

        List<GoodsReviewAppVO> rows = goodsAppService.listReviews(1L);

        assertEquals(1, rows.size());
        assertEquals(1L, rows.get(0).getReviewId());
        assertEquals("张三", rows.get(0).getMemberNickName());
        assertEquals(2, rows.get(0).getPics().size());
    }

    @Test
    void listReviews_returnsEmptyWhenNoRows()
    {
        when(reviewMapper.selectByGoodsId(1L)).thenReturn(Collections.emptyList());

        assertTrue(goodsAppService.listReviews(1L).isEmpty());
    }

    private static GoodsDetailBaseDTO sampleBase()
    {
        GoodsDetailBaseDTO base = new GoodsDetailBaseDTO();
        base.setGoodsId(1L);
        base.setGoodsSn("G001");
        base.setGoodsName("阿莫西林");
        base.setMainPic("/main.jpg");
        base.setDetailContent("<p>详情</p>");
        base.setSalePrice(new BigDecimal("88.00"));
        base.setStock(100);
        base.setSalesCount(50);
        base.setGoodsStatus(GoodsConstants.STATUS_ON_SALE);
        base.setCategoryId(10L);
        base.setShopId(101L);
        base.setShopName("测试店铺");
        base.setShopAvatar("/avatar.jpg");
        base.setShopStatus("0");
        base.setShopPhone("13800000000");
        return base;
    }
}
