package com.ruoyi.web.modules.merchant.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.eq;
import static org.mockito.ArgumentMatchers.anyList;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.junit.jupiter.api.Test;
import com.ruoyi.web.modules.merchant.vo.OpenShopCheckVO;
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.constant.MerchantConstants;
import com.ruoyi.web.modules.merchant.domain.BizMerchant;
import com.ruoyi.web.modules.merchant.dto.MerchantCertStatusDTO;
import com.ruoyi.web.modules.merchant.dto.MerchantCreateDTO;
import com.ruoyi.web.modules.merchant.service.IMerchantAccountBindService;
import com.ruoyi.web.modules.merchant.exception.MerchantBatchDeleteException;
import com.ruoyi.web.modules.merchant.facade.IMerchantOrderFacade;
import com.ruoyi.web.modules.merchant.facade.IMerchantShopFacade;
import com.ruoyi.web.modules.merchant.mapper.BizMerchantMapper;
import com.ruoyi.web.modules.merchant.service.impl.MerchantServiceImpl;
import com.ruoyi.web.modules.merchant.vo.MerchantListVO;
import com.ruoyi.web.modules.store.mapper.BizMerchantAccountMapper;
import com.ruoyi.web.modules.store.vo.MerchantAccountUserVO;

@ExtendWith(MockitoExtension.class)
class MerchantServiceImplTest
{
    @Mock
    private BizMerchantMapper merchantMapper;

    @Mock
    private IMerchantOrderFacade orderFacade;

    @Mock
    private IMerchantShopFacade shopFacade;

    @Mock
    private IMerchantAccountBindService accountBindService;

    @Mock
    private BizMerchantAccountMapper merchantAccountMapper;

    @InjectMocks
    private MerchantServiceImpl merchantService;

    @Test
    void selectMerchantList_fillsAdminName()
    {
        BizMerchant merchant = new BizMerchant();
        merchant.setMerchantId(1L);
        merchant.setMerchantType(MerchantConstants.TYPE_PERSON);
        merchant.setPersonName("张三");
        merchant.setShopCount(0);
        when(merchantMapper.selectList(any())).thenReturn(Collections.singletonList(merchant));
        when(orderFacade.hasUnfinishedOrdersByMerchant(1L)).thenReturn(false);

        MerchantAccountUserVO admin = new MerchantAccountUserVO();
        admin.setMerchantId(1L);
        admin.setAdminName("张管理员");
        when(merchantAccountMapper.selectMerchantAdminNamesByMerchantIds(anyList()))
                .thenReturn(Collections.singletonList(admin));

        List<MerchantListVO> rows = merchantService.selectMerchantList(new BizMerchant());

        assertEquals(1, rows.size());
        assertEquals("张管理员", rows.get(0).getAdminName());
    }

    @Test
    void insert_setsCertNormalAndBizComplete_whenBizFieldsComplete()
    {
        MerchantCreateDTO dto = fullPersonCreateDto();
        when(merchantMapper.countByIdCardNo(any(), eq(null))).thenReturn(0);
        when(merchantMapper.countByMerchantName(any(), eq(null))).thenReturn(0);
        when(merchantMapper.insert(any())).thenAnswer(inv -> {
            BizMerchant m = inv.getArgument(0);
            m.setMerchantId(1L);
            return 1;
        });

        merchantService.insertMerchant(dto, "admin");

        verify(accountBindService).bindAccountOnMerchantCreate(eq(1L), eq(dto), eq("admin"));

        assertEquals(MerchantConstants.CERT_NORMAL, dto.getCertStatus());
        assertEquals(MerchantConstants.BIZ_COMPLETE, dto.getBizComplete());
        assertEquals(0, dto.getShopCount());
    }

    @Test
    void insert_rejectsIncompleteBiz()
    {
        MerchantCreateDTO dto = new MerchantCreateDTO();
        dto.setMerchantType(MerchantConstants.TYPE_PERSON);
        dto.setPersonName("张三");
        dto.setIdCardNo("110101199001011234");
        dto.setBindType("SYS_USER");
        dto.setBindUserId(10L);
        when(merchantMapper.countByIdCardNo(any(), eq(null))).thenReturn(0);

        ServiceException ex = assertThrows(ServiceException.class,
                () -> merchantService.insertMerchant(dto, "admin"));
        assertTrue(ex.getMessage().contains("经营信息不完整"));
        verify(merchantMapper, never()).insert(any());
    }

    @Test
    void insert_rejectsDuplicateIdCard()
    {
        MerchantCreateDTO dto = fullPersonCreateDto();
        when(merchantMapper.countByIdCardNo(any(), eq(null))).thenReturn(1);

        ServiceException ex = assertThrows(ServiceException.class,
                () -> merchantService.insertMerchant(dto, "admin"));
        assertEquals("该证件号码已入驻", ex.getMessage());
        verify(merchantMapper, never()).insert(any());
    }

    private MerchantCreateDTO fullPersonCreateDto()
    {
        MerchantCreateDTO dto = new MerchantCreateDTO();
        dto.setMerchantType(MerchantConstants.TYPE_PERSON);
        dto.setPersonName("张三");
        dto.setIdCardNo("110101199001011234");
        dto.setMerchantName("张三农资");
        dto.setServicePhone("400-800");
        dto.setBizRegionCode("110");
        dto.setBizRegionName("北京");
        dto.setBizDetailAddress("路1号");
        dto.setContactName("张三");
        dto.setContactPhone("13800138000");
        dto.setContactEmail("a@b.com");
        dto.setBankName("工行");
        dto.setBankBranch("支行");
        dto.setBankAccount("6222021234567890");
        dto.setBindType("SYS_USER");
        dto.setBindUserId(10L);
        return dto;
    }

    @Test
    void update_cancelledMerchant_rejected()
    {
        BizMerchant existing = new BizMerchant();
        existing.setMerchantId(1L);
        existing.setCertStatus(MerchantConstants.CERT_CANCELLED);
        when(merchantMapper.selectById(1L)).thenReturn(existing);

        BizMerchant update = new BizMerchant();
        update.setMerchantId(1L);
        assertThrows(ServiceException.class, () -> merchantService.updateMerchant(update, "admin"));
    }

    @Test
    void certStatus_needConfirm_whenNotConfirmed()
    {
        BizMerchant existing = new BizMerchant();
        existing.setMerchantId(1L);
        existing.setCertStatus(MerchantConstants.CERT_NORMAL);
        when(merchantMapper.selectById(1L)).thenReturn(existing);

        MerchantCertStatusDTO dto = new MerchantCertStatusDTO();
        dto.setCertStatus(MerchantConstants.CERT_FROZEN);
        dto.setConfirm(false);

        Map<String, Object> data = merchantService.updateCertStatus(1L, dto, "admin");
        assertTrue((Boolean) data.get("needConfirm"));
        verify(merchantMapper, never()).updateCertStatus(any(), any());
    }

    @Test
    void delete_withShops_rejected()
    {
        BizMerchant m = new BizMerchant();
        m.setMerchantId(1L);
        m.setCertStatus(MerchantConstants.CERT_NORMAL);
        m.setShopCount(2);
        when(merchantMapper.selectById(1L)).thenReturn(m);
        when(orderFacade.hasUnfinishedOrdersByMerchant(1L)).thenReturn(false);

        assertThrows(MerchantBatchDeleteException.class,
                () -> merchantService.deleteMerchantByIds(new Long[] { 1L }, "admin"));
    }

    @Test
    void openShopCheck_bizIncomplete()
    {
        BizMerchant m = new BizMerchant();
        m.setMerchantId(1L);
        m.setCertStatus(MerchantConstants.CERT_NORMAL);
        m.setBizComplete(MerchantConstants.BIZ_INCOMPLETE);
        when(merchantMapper.selectById(1L)).thenReturn(m);

        OpenShopCheckVO vo = merchantService.openShopCheck(1L);
        assertEquals(false, vo.isAllowed());
        assertEquals("经营信息未完善", vo.getReason());
    }
}
