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

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
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.isNull;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.util.Map;
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.merchant.facade.IMerchantFacade;
import com.ruoyi.web.modules.merchant.facade.IMerchantShopFacade;
import com.ruoyi.web.modules.merchant.mapper.BizMerchantMapper;
import com.ruoyi.web.modules.merchant.vo.OpenShopCheckVO;
import com.ruoyi.web.modules.store.constant.ShopConstants;
import com.ruoyi.web.modules.store.domain.BizMerchantAccount;
import com.ruoyi.web.modules.store.domain.BizShop;
import com.ruoyi.web.modules.store.dto.SellerShopProfileDTO;
import com.ruoyi.web.modules.store.dto.ShopCreateDTO;
import com.ruoyi.web.modules.store.dto.ShopUpdateDTO;
import com.ruoyi.web.modules.store.facade.IGoodsShopFacade;
import com.ruoyi.web.modules.store.facade.IShopOrderFacade;
import com.ruoyi.web.modules.store.mapper.BizMerchantAccountMapper;
import com.ruoyi.web.modules.store.mapper.BizShopMapper;
import com.ruoyi.web.modules.store.service.impl.ShopServiceImpl;

@ExtendWith(MockitoExtension.class)
class ShopServiceImplTest
{
    @Mock
    private BizShopMapper shopMapper;

    @Mock
    private BizMerchantAccountMapper accountMapper;

    @Mock
    private BizMerchantMapper merchantMapper;

    @Mock
    private IMerchantFacade merchantFacade;

    @Mock
    private IMerchantShopFacade merchantShopFacade;

    @Mock
    private IGoodsShopFacade goodsShopFacade;

    @Mock
    private IShopOrderFacade shopOrderFacade;

    @InjectMocks
    private ShopServiceImpl shopService;

    @Test
    void createShop_firstShop_insertsAccountAndShop()
    {
        ShopCreateDTO dto = buildCreateDto();
        OpenShopCheckVO allowed = new OpenShopCheckVO();
        allowed.setAllowed(true);
        when(merchantFacade.checkOpenShop(1L)).thenReturn(allowed);
        when(shopMapper.countByShopName(eq("测试店"), isNull())).thenReturn(0);
        when(accountMapper.selectByMerchantId(1L)).thenReturn(null);
        when(accountMapper.countByLoginName(eq("13800138000"), isNull())).thenReturn(0);
        when(shopMapper.insert(any())).thenAnswer(inv -> {
            BizShop s = inv.getArgument(0);
            s.setShopId(10L);
            return 1;
        });

        Long shopId = shopService.createShop(dto, "admin");

        assertEquals(10L, shopId);
        verify(accountMapper).insert(any(BizMerchantAccount.class));
        verify(shopMapper).insert(any(BizShop.class));
        verify(merchantShopFacade).incrementShopCount(1L);
    }

    @Test
    void createShop_secondShop_noNewAccount()
    {
        ShopCreateDTO dto = buildCreateDto();
        dto.setPassword(null);
        BizMerchantAccount account = new BizMerchantAccount();
        account.setMerchantId(1L);
        account.setLoginName("13800138000");
        account.setAdminName("张三");
        OpenShopCheckVO allowed = new OpenShopCheckVO();
        allowed.setAllowed(true);
        when(merchantFacade.checkOpenShop(1L)).thenReturn(allowed);
        when(shopMapper.countByShopName(any(), isNull())).thenReturn(0);
        when(accountMapper.selectByMerchantId(1L)).thenReturn(account);
        when(shopMapper.insert(any())).thenAnswer(inv -> {
            BizShop s = inv.getArgument(0);
            s.setShopId(11L);
            return 1;
        });

        shopService.createShop(dto, "admin");

        verify(accountMapper, never()).insert(any());
        verify(merchantShopFacade).incrementShopCount(1L);
    }

    @Test
    void createShop_loginMismatch_rejected()
    {
        ShopCreateDTO dto = buildCreateDto();
        dto.setLoginName("13900139000");
        BizMerchantAccount account = new BizMerchantAccount();
        account.setLoginName("13800138000");
        OpenShopCheckVO allowed = new OpenShopCheckVO();
        allowed.setAllowed(true);
        when(merchantFacade.checkOpenShop(1L)).thenReturn(allowed);
        when(shopMapper.countByShopName(any(), isNull())).thenReturn(0);
        when(accountMapper.selectByMerchantId(1L)).thenReturn(account);

        ServiceException ex = assertThrows(ServiceException.class,
                () -> shopService.createShop(dto, "admin"));
        assertEquals(ShopConstants.MSG_ACCOUNT_MISMATCH, ex.getMessage());
    }

    @Test
    void createShop_duplicateShopName_rejected()
    {
        ShopCreateDTO dto = buildCreateDto();
        OpenShopCheckVO allowed = new OpenShopCheckVO();
        allowed.setAllowed(true);
        when(merchantFacade.checkOpenShop(1L)).thenReturn(allowed);
        when(shopMapper.countByShopName(eq("测试店"), isNull())).thenReturn(1);

        assertThrows(ServiceException.class, () -> shopService.createShop(dto, "admin"));
    }

    @Test
    void createShop_openShopNotAllowed_rejected()
    {
        ShopCreateDTO dto = buildCreateDto();
        OpenShopCheckVO denied = new OpenShopCheckVO();
        denied.setAllowed(false);
        denied.setReason("经营信息未完善");
        when(merchantFacade.checkOpenShop(1L)).thenReturn(denied);

        ServiceException ex = assertThrows(ServiceException.class,
                () -> shopService.createShop(dto, "admin"));
        assertEquals("经营信息未完善", ex.getMessage());
        verify(shopMapper, never()).insert(any());
    }

    @Test
    void updateSellerShopProfile_updatesBizShopRow()
    {
        when(shopMapper.selectById(1L)).thenReturn(openShop(1L));
        when(shopMapper.countByShopName(eq("新店名"), eq(1L))).thenReturn(0);
        SellerShopProfileDTO dto = new SellerShopProfileDTO();
        dto.setShopName("新店名");
        dto.setShopAvatar("/new.jpg");
        dto.setShopPhone("010-88886667");
        dto.setShopDesc("描述");

        shopService.updateSellerShopProfile(1L, dto, "seller");

        verify(shopMapper).update(any(BizShop.class));
    }

    @Test
    void updateShop_closeWithoutConfirm_returnsNeedConfirm()
    {
        BizShop existing = openShop(1L);
        when(shopMapper.selectById(1L)).thenReturn(existing);
        ShopUpdateDTO dto = new ShopUpdateDTO();
        dto.setShopId(1L);
        dto.setShopStatus(ShopConstants.STATUS_CLOSED);
        dto.setConfirm(false);

        Map<String, Object> data = shopService.updateShop(dto, "admin");

        assertTrue((Boolean) data.get("needConfirm"));
        verify(shopMapper, never()).update(any());
    }

    @Test
    void updateShop_closeWithConfirm_persists()
    {
        BizShop existing = openShop(1L);
        when(shopMapper.selectById(1L)).thenReturn(existing);
        ShopUpdateDTO dto = new ShopUpdateDTO();
        dto.setShopId(1L);
        dto.setShopStatus(ShopConstants.STATUS_CLOSED);
        dto.setConfirm(true);

        Map<String, Object> data = shopService.updateShop(dto, "admin");

        assertFalse((Boolean) data.get("needConfirm"));
        verify(shopMapper).update(any(BizShop.class));
    }

    @Test
    void updateShop_reopen_noConfirmRequired()
    {
        BizShop existing = openShop(1L);
        existing.setShopStatus(ShopConstants.STATUS_CLOSED);
        when(shopMapper.selectById(1L)).thenReturn(existing);
        ShopUpdateDTO dto = new ShopUpdateDTO();
        dto.setShopId(1L);
        dto.setShopStatus(ShopConstants.STATUS_OPEN);

        shopService.updateShop(dto, "admin");

        verify(shopMapper).update(any(BizShop.class));
    }

    private ShopCreateDTO buildCreateDto()
    {
        ShopCreateDTO dto = new ShopCreateDTO();
        dto.setMerchantId(1L);
        dto.setShopName("测试店");
        dto.setShopAvatar("/profile/upload/a.jpg");
        dto.setShopPhone("010-88886666");
        dto.setLoginName("13800138000");
        dto.setAdminName("张三");
        dto.setPassword("123456");
        return dto;
    }

    private BizShop openShop(Long shopId)
    {
        BizShop shop = new BizShop();
        shop.setShopId(shopId);
        shop.setMerchantId(1L);
        shop.setShopStatus(ShopConstants.STATUS_OPEN);
        shop.setShopName("店");
        shop.setShopAvatar("/a.jpg");
        shop.setShopPhone("010-88886666");
        return shop;
    }
}
