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

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.util.Collections;
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.SysRole;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.system.service.ISysRoleService;
import com.ruoyi.web.modules.role.constant.MerchantRoleConstants;
import com.ruoyi.web.modules.role.domain.MerchantRoleQuery;
import com.ruoyi.web.modules.role.domain.MerchantRoleRow;
import com.ruoyi.web.modules.role.dto.MerchantRoleCreateDTO;
import com.ruoyi.web.modules.role.mapper.MerchantRoleMapper;
import com.ruoyi.web.modules.role.service.impl.MerchantRoleServiceImpl;
import com.ruoyi.web.modules.role.support.MerchantRoleSupport;
import com.ruoyi.web.modules.role.vo.MerchantRoleListVO;

@ExtendWith(MockitoExtension.class)
class MerchantRoleServiceImplTest
{
    private static final Long MERCHANT_ID = 1L;

    private static final Long SHOP_ID = 101L;

    @Mock
    private MerchantRoleMapper merchantRoleMapper;

    @Mock
    private MerchantRoleSupport merchantRoleSupport;

    @Mock
    private ISysRoleService sysRoleService;

    @InjectMocks
    private MerchantRoleServiceImpl merchantRoleService;

    @Test
    void selectRoleList_scopesByCurrentShop()
    {
        MerchantRoleRow row = new MerchantRoleRow();
        row.setRoleId(401L);
        row.setRoleName("店员");
        row.setStatus(MerchantRoleConstants.STATUS_NORMAL);
        row.setBindCount(1);

        MerchantRoleQuery query = new MerchantRoleQuery();
        query.setShopId(SHOP_ID);
        when(merchantRoleMapper.selectList(any(MerchantRoleQuery.class)))
                .thenReturn(Collections.singletonList(row));

        MerchantRoleListVO vo = merchantRoleService.selectRoleList(query).get(0);

        assertEquals(401L, vo.getRoleId());
        assertEquals("店员", vo.getRoleName());
        assertEquals(Integer.valueOf(1), vo.getBindCount());
    }

    @Test
    void fillListScope_setsCurrentShop()
    {
        MerchantRoleQuery query = new MerchantRoleQuery();
        when(merchantRoleSupport.requireMerchantId(10L)).thenReturn(MERCHANT_ID);
        when(merchantRoleSupport.requireCurrentShopId(MERCHANT_ID)).thenReturn(SHOP_ID);

        merchantRoleService.fillListScope(query, 10L);

        assertEquals(SHOP_ID, query.getShopId());
    }

    @Test
    void createRole_insertsSysRoleAndShopBinding()
    {
        MerchantRoleCreateDTO dto = buildCreateDto();
        when(merchantRoleSupport.requireMerchantId(10L)).thenReturn(MERCHANT_ID);
        when(merchantRoleSupport.requireCurrentShopId(MERCHANT_ID)).thenReturn(SHOP_ID);
        when(merchantRoleSupport.generateRoleKey(SHOP_ID)).thenReturn("seller_s101_abcd1234");

        org.mockito.Mockito.doAnswer(invocation -> {
            SysRole role = invocation.getArgument(0);
            role.setRoleId(401L);
            return 1;
        }).when(sysRoleService).insertRole(any(SysRole.class));

        Long roleId = merchantRoleService.createRole(dto, 10L, "admin");

        assertEquals(401L, roleId);
        verify(merchantRoleSupport).validateCreate(dto, SHOP_ID);
        verify(sysRoleService).insertRole(any(SysRole.class));
        verify(merchantRoleMapper).insertShopRole(SHOP_ID, 401L);
    }

    @Test
    void deleteRoles_blocksBoundRole()
    {
        MerchantRoleRow row = new MerchantRoleRow();
        row.setRoleId(401L);

        when(merchantRoleSupport.requireMerchantId(10L)).thenReturn(MERCHANT_ID);
        when(merchantRoleSupport.requireCurrentShopId(MERCHANT_ID)).thenReturn(SHOP_ID);
        when(merchantRoleSupport.requireRoleRow(SHOP_ID, 401L)).thenReturn(row);
        org.mockito.Mockito.doThrow(new ServiceException(MerchantRoleConstants.MSG_ROLE_BOUND))
                .when(merchantRoleSupport).assertDeletable(SHOP_ID, 401L);

        assertThrows(ServiceException.class,
                () -> merchantRoleService.deleteRoles(new Long[] { 401L }, 10L));

        verify(merchantRoleMapper, never()).deleteShopRole(eq(SHOP_ID), eq(401L));
    }

    private MerchantRoleCreateDTO buildCreateDto()
    {
        MerchantRoleCreateDTO dto = new MerchantRoleCreateDTO();
        dto.setRoleName("店员");
        dto.setRoleDesc("负责商品");
        dto.setStatus(MerchantRoleConstants.STATUS_NORMAL);
        dto.setMenuIds(new Long[] { 6001L });
        return dto;
    }
}
