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

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.anyList;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.lenient;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.junit.jupiter.api.AfterEach;
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.category.facade.IGoodsFacade;
import com.ruoyi.web.modules.category.facade.IShopFacade;
import com.ruoyi.web.modules.category.support.SellerShopContext;
import com.ruoyi.web.modules.template.constant.AttrTemplateConstants;
import com.ruoyi.web.modules.template.domain.BizGoodsAttrTemplate;
import com.ruoyi.web.modules.template.domain.BizGoodsAttrTemplateItem;
import com.ruoyi.web.modules.template.domain.BizGoodsAttrTemplateValue;
import com.ruoyi.web.modules.template.dto.AttrTemplateItemDTO;
import com.ruoyi.web.modules.template.dto.AttrTemplateSaveDTO;
import com.ruoyi.web.modules.template.exception.AttrTemplateBatchDeleteException;
import com.ruoyi.web.modules.template.mapper.BizGoodsAttrTemplateItemMapper;
import com.ruoyi.web.modules.template.mapper.BizGoodsAttrTemplateMapper;
import com.ruoyi.web.modules.template.mapper.BizGoodsAttrTemplateValueMapper;
import com.ruoyi.web.modules.template.service.impl.AttrTemplateServiceImpl;
import com.ruoyi.web.modules.template.vo.AttrTemplateDetailVO;
import com.ruoyi.web.modules.template.vo.AttrTemplateListVO;

@ExtendWith(MockitoExtension.class)
class AttrTemplateServiceImplTest
{
    private static final Long SHOP_ID = 101L;

    @Mock
    private BizGoodsAttrTemplateMapper templateMapper;

    @Mock
    private BizGoodsAttrTemplateItemMapper itemMapper;

    @Mock
    private BizGoodsAttrTemplateValueMapper valueMapper;

    @Mock
    private IGoodsFacade goodsFacade;

    @Mock
    private IShopFacade shopFacade;

    @InjectMocks
    private AttrTemplateServiceImpl attrTemplateService;

    @BeforeEach
    void setUp()
    {
        SellerShopContext.setShopId(SHOP_ID);
        lenient().doNothing().when(shopFacade).assertShopMaintable(SHOP_ID);
    }

    @AfterEach
    void tearDown()
    {
        SellerShopContext.clear();
    }

    @Test
    void selectTemplateList_scopedToShop()
    {
        BizGoodsAttrTemplate template = new BizGoodsAttrTemplate();
        template.setTemplateId(1L);
        template.setTemplateName("宠物");
        when(templateMapper.selectList(any())).thenReturn(Collections.singletonList(template));
        BizGoodsAttrTemplateItem item = new BizGoodsAttrTemplateItem();
        item.setTemplateId(1L);
        item.setItemType(AttrTemplateConstants.ITEM_TYPE_ATTR);
        item.setItemName("类型");
        item.setSortNo(0);
        when(itemMapper.selectByTemplateIds(anyList())).thenReturn(Collections.singletonList(item));

        List<AttrTemplateListVO> rows = attrTemplateService.selectTemplateList(null);

        assertEquals(1, rows.size());
        assertEquals("类型", rows.get(0).getNameList());
    }

    @Test
    void requireShopId_missingFails()
    {
        SellerShopContext.clear();
        ServiceException ex = assertThrows(ServiceException.class,
                () -> attrTemplateService.selectTemplateList(null));
        assertTrue(ex.getMessage().contains("请先选择当前店铺"));
    }

    @Test
    void insertTemplate_success()
    {
        when(templateMapper.countByName(eq(SHOP_ID), eq("家电"), isNull())).thenReturn(0);
        when(templateMapper.insert(any())).thenAnswer(invocation -> {
            BizGoodsAttrTemplate t = invocation.getArgument(0);
            t.setTemplateId(10L);
            return 1;
        });
        when(itemMapper.insert(any())).thenAnswer(invocation -> {
            BizGoodsAttrTemplateItem item = invocation.getArgument(0);
            item.setItemId(100L);
            return 1;
        });

        AttrTemplateSaveDTO dto = saveDto("家电",
                item("功率", "1000W"),
                null);

        assertEquals(1, attrTemplateService.insertTemplate(dto, "tester"));
        verify(valueMapper).insert(any());
    }

    @Test
    void insertTemplate_duplicateNameFails()
    {
        when(templateMapper.countByName(eq(SHOP_ID), eq("宠物"), isNull())).thenReturn(1);
        AttrTemplateSaveDTO dto = saveDto("宠物", item("类型", "犬类"), null);
        ServiceException ex = assertThrows(ServiceException.class,
                () -> attrTemplateService.insertTemplate(dto, "tester"));
        assertTrue(ex.getMessage().contains("属性模版名称已存在"));
    }

    @Test
    void insertTemplate_noItemFails()
    {
        AttrTemplateSaveDTO dto = new AttrTemplateSaveDTO();
        dto.setTemplateName("空结构");
        dto.setAttributes(Collections.emptyList());
        dto.setSpecs(Collections.emptyList());
        ServiceException ex = assertThrows(ServiceException.class,
                () -> attrTemplateService.insertTemplate(dto, "tester"));
        assertTrue(ex.getMessage().contains("请至少添加一个属性项或规格项"));
    }

    @Test
    void insertTemplate_crossSectionNameFails()
    {
        AttrTemplateSaveDTO dto = saveDto("手机",
                item("颜色", "红"),
                item("颜色", "128G"));
        ServiceException ex = assertThrows(ServiceException.class,
                () -> attrTemplateService.insertTemplate(dto, "tester"));
        assertTrue(ex.getMessage().contains("属性项与规格项名称不可相同"));
    }

    @Test
    void insertTemplate_duplicateValueFails()
    {
        AttrTemplateItemDTO attr = new AttrTemplateItemDTO();
        attr.setItemName("品牌");
        attr.setValues(Arrays.asList("小米", "小米"));
        AttrTemplateSaveDTO dto = saveDto("手机", attr, null);
        ServiceException ex = assertThrows(ServiceException.class,
                () -> attrTemplateService.insertTemplate(dto, "tester"));
        assertTrue(ex.getMessage().contains("不可重复"));
    }

    @Test
    void updateTemplate_replacesItems()
    {
        BizGoodsAttrTemplate existing = new BizGoodsAttrTemplate();
        existing.setTemplateId(2L);
        existing.setTemplateName("手机");
        when(templateMapper.selectById(2L, SHOP_ID)).thenReturn(existing);
        when(templateMapper.countByName(eq(SHOP_ID), eq("手机Pro"), eq(2L))).thenReturn(0);

        AttrTemplateSaveDTO dto = saveDto("手机Pro", item("屏幕", "2K"), null);
        dto.setTemplateId(2L);

        assertEquals(1, attrTemplateService.updateTemplate(dto, "tester"));
        verify(valueMapper).deleteByTemplateId(2L);
        verify(itemMapper).deleteByTemplateId(2L);
        verify(itemMapper).insert(any());
    }

    @Test
    void deleteTemplate_inUseFailsBatch()
    {
        BizGoodsAttrTemplate template = new BizGoodsAttrTemplate();
        template.setTemplateId(4L);
        template.setTemplateName("引用中");
        when(templateMapper.selectById(4L, SHOP_ID)).thenReturn(template);
        when(goodsFacade.existsByAttrTemplateId(4L)).thenReturn(true);

        assertThrows(AttrTemplateBatchDeleteException.class,
                () -> attrTemplateService.deleteTemplateByIds(new Long[] { 4L }, "tester"));
        verify(templateMapper, never()).logicDeleteByIds(anyList(), eq(SHOP_ID), any());
    }

    @Test
    void deleteTemplate_success()
    {
        BizGoodsAttrTemplate template = new BizGoodsAttrTemplate();
        template.setTemplateId(3L);
        template.setTemplateName("待删");
        when(templateMapper.selectById(3L, SHOP_ID)).thenReturn(template);
        when(goodsFacade.existsByAttrTemplateId(3L)).thenReturn(false);

        attrTemplateService.deleteTemplateByIds(new Long[] { 3L }, "tester");

        verify(valueMapper).deleteByTemplateId(3L);
        verify(itemMapper).deleteByTemplateId(3L);
        verify(templateMapper).logicDeleteByIds(eq(Collections.singletonList(3L)), eq(SHOP_ID), eq("tester"));
    }

    @Test
    void selectTemplateDetail_splitsAttributesAndSpecs()
    {
        BizGoodsAttrTemplate template = new BizGoodsAttrTemplate();
        template.setTemplateId(2L);
        template.setTemplateName("手机");
        when(templateMapper.selectById(2L, SHOP_ID)).thenReturn(template);

        BizGoodsAttrTemplateItem attrItem = new BizGoodsAttrTemplateItem();
        attrItem.setItemId(11L);
        attrItem.setItemType(AttrTemplateConstants.ITEM_TYPE_ATTR);
        attrItem.setItemName("品牌");
        BizGoodsAttrTemplateItem specItem = new BizGoodsAttrTemplateItem();
        specItem.setItemId(12L);
        specItem.setItemType(AttrTemplateConstants.ITEM_TYPE_SPEC);
        specItem.setItemName("颜色");
        when(itemMapper.selectByTemplateId(2L)).thenReturn(Arrays.asList(attrItem, specItem));

        BizGoodsAttrTemplateValue v1 = new BizGoodsAttrTemplateValue();
        v1.setItemId(11L);
        v1.setValueText("小米");
        BizGoodsAttrTemplateValue v2 = new BizGoodsAttrTemplateValue();
        v2.setItemId(12L);
        v2.setValueText("红");
        when(valueMapper.selectByItemIds(anyList())).thenReturn(Arrays.asList(v1, v2));

        AttrTemplateDetailVO detail = attrTemplateService.selectTemplateDetail(2L);

        assertEquals(1, detail.getAttributes().size());
        assertEquals(1, detail.getSpecs().size());
        assertEquals("小米", detail.getAttributes().get(0).getValues().get(0));
    }

    @Test
    void buildNameList_attrBeforeSpec()
    {
        BizGoodsAttrTemplate template = new BizGoodsAttrTemplate();
        template.setTemplateId(2L);
        template.setTemplateName("手机");
        when(templateMapper.selectList(any())).thenReturn(Collections.singletonList(template));

        BizGoodsAttrTemplateItem spec = new BizGoodsAttrTemplateItem();
        spec.setTemplateId(2L);
        spec.setItemType(AttrTemplateConstants.ITEM_TYPE_SPEC);
        spec.setItemName("颜色");
        BizGoodsAttrTemplateItem attr = new BizGoodsAttrTemplateItem();
        attr.setTemplateId(2L);
        attr.setItemType(AttrTemplateConstants.ITEM_TYPE_ATTR);
        attr.setItemName("品牌");
        when(itemMapper.selectByTemplateIds(anyList())).thenReturn(Arrays.asList(attr, spec));

        List<AttrTemplateListVO> rows = attrTemplateService.selectTemplateList(null);
        assertEquals("品牌,颜色", rows.get(0).getNameList());
    }

    private static AttrTemplateSaveDTO saveDto(String name, AttrTemplateItemDTO attr, AttrTemplateItemDTO spec)
    {
        AttrTemplateSaveDTO dto = new AttrTemplateSaveDTO();
        dto.setTemplateName(name);
        if (attr != null)
        {
            dto.setAttributes(Collections.singletonList(attr));
        }
        if (spec != null)
        {
            dto.setSpecs(Collections.singletonList(spec));
        }
        return dto;
    }

    private static AttrTemplateItemDTO item(String itemName, String... values)
    {
        AttrTemplateItemDTO dto = new AttrTemplateItemDTO();
        dto.setItemName(itemName);
        dto.setValues(Arrays.asList(values));
        return dto;
    }
}
