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

import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
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.core.domain.entity.SysUser;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.web.modules.account.constant.MemberConstants;
import com.ruoyi.web.modules.account.domain.BizMember;
import com.ruoyi.web.modules.account.mapper.BizMemberMapper;
import com.ruoyi.web.modules.merchant.constant.MerchantBindConstants;
import com.ruoyi.web.modules.merchant.dto.MerchantCreateDTO;
import com.ruoyi.web.modules.merchant.mapper.MerchantBindMapper;
import com.ruoyi.web.modules.merchant.service.impl.MerchantAccountBindServiceImpl;
import com.ruoyi.web.modules.store.mapper.BizMerchantAccountMapper;
import com.ruoyi.system.service.ISysUserService;
import com.ruoyi.web.modules.account.support.MemberSysUserSupport;

@ExtendWith(MockitoExtension.class)
class MerchantAccountBindServiceImplTest
{
    @Mock
    private MerchantBindMapper merchantBindMapper;

    @Mock
    private BizMerchantAccountMapper merchantAccountMapper;

    @Mock
    private BizMemberMapper memberMapper;

    @Mock
    private ISysUserService sysUserService;

    @Mock
    private MemberSysUserSupport memberSysUserSupport;

    @InjectMocks
    private MerchantAccountBindServiceImpl bindService;

    @Test
    void bindFromSysUser_insertsMerchantAccount()
    {
        SysUser user = new SysUser();
        user.setUserId(10L);
        user.setUserName("admin01");
        user.setNickName("管理员甲");
        user.setPassword("hash");
        when(sysUserService.selectUserById(10L)).thenReturn(user);
        when(merchantBindMapper.countUserHasRole(10L, MerchantBindConstants.MERCHANT_ADMIN_ROLE_KEY)).thenReturn(1);
        when(merchantAccountMapper.countByAccountId(10L)).thenReturn(0);

        MerchantCreateDTO dto = new MerchantCreateDTO();
        dto.setBindType(MerchantBindConstants.BIND_SYS_USER);
        dto.setBindUserId(10L);

        bindService.bindAccountOnMerchantCreate(1L, dto, "op");

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

    @Test
    void bind_missingBindType_throws()
    {
        MerchantCreateDTO dto = new MerchantCreateDTO();
        assertThrows(ServiceException.class, () -> bindService.bindAccountOnMerchantCreate(1L, dto, "op"));
    }

    @Test
    void bindFromMember_requiresNickName()
    {
        BizMember member = new BizMember();
        member.setMemberId(5L);
        member.setMemberCode("张三");
        member.setNickName("");
        when(memberMapper.selectById(5L)).thenReturn(member);
        SysUser user = new SysUser();
        user.setUserId(5L);
        when(sysUserService.selectUserById(5L)).thenReturn(user);
        when(merchantBindMapper.countUserHasRole(5L, MemberConstants.MEMBER_ROLE_KEY)).thenReturn(1);

        MerchantCreateDTO dto = new MerchantCreateDTO();
        dto.setBindType(MerchantBindConstants.BIND_MEMBER);
        dto.setBindMemberId(5L);

        assertThrows(ServiceException.class, () -> bindService.bindAccountOnMerchantCreate(1L, dto, "op"));
    }

    @Test
    void bindFromMember_requiresMemberName()
    {
        BizMember member = new BizMember();
        member.setMemberId(5L);
        member.setMemberCode("");
        member.setNickName("小张");
        when(memberMapper.selectById(5L)).thenReturn(member);
        when(sysUserService.selectUserById(5L)).thenReturn(new SysUser());
        when(merchantBindMapper.countUserHasRole(5L, MemberConstants.MEMBER_ROLE_KEY)).thenReturn(1);

        MerchantCreateDTO dto = new MerchantCreateDTO();
        dto.setBindType(MerchantBindConstants.BIND_MEMBER);
        dto.setBindMemberId(5L);

        assertThrows(ServiceException.class, () -> bindService.bindAccountOnMerchantCreate(1L, dto, "op"));
    }

    @Test
    void bindFromMember_reusesMemberSysUser()
    {
        BizMember member = new BizMember();
        member.setMemberId(5L);
        member.setMemberCode("张三");
        member.setNickName("小张");
        when(memberMapper.selectById(5L)).thenReturn(member);
        SysUser user = new SysUser();
        user.setUserId(5L);
        user.setPassword("hash");
        when(sysUserService.selectUserById(5L)).thenReturn(user);
        when(merchantBindMapper.countUserHasRole(5L, MemberConstants.MEMBER_ROLE_KEY)).thenReturn(1);
        when(merchantAccountMapper.countByAccountId(5L)).thenReturn(0);

        MerchantCreateDTO dto = new MerchantCreateDTO();
        dto.setBindType(MerchantBindConstants.BIND_MEMBER);
        dto.setBindMemberId(5L);

        bindService.bindAccountOnMerchantCreate(1L, dto, "op");

        verify(memberSysUserSupport).grantRoleIfAbsent(5L, MerchantBindConstants.MERCHANT_ADMIN_ROLE_KEY);
        verify(merchantAccountMapper).insert(any());
    }
}
