package tech.easyflow.system.service.impl;

import com.mybatisflex.core.query.QueryWrapper;
import org.junit.Test;
import tech.easyflow.common.constant.enums.EnumDataStatus;
import tech.easyflow.system.entity.SysAccountRole;
import tech.easyflow.system.entity.SysRole;
import tech.easyflow.system.service.SysAccountRoleService;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.math.BigInteger;
import java.util.Collection;
import java.util.List;

import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

/**
 * {@link SysRoleServiceImpl} 角色状态过滤测试。
 */
public class SysRoleServiceImplTest {

    /**
     * 验证账号角色查询只返回启用角色。
     *
     * @throws Exception 注入测试依赖失败
     */
    @Test
    public void getRolesByAccountIdShouldExcludeUnavailableRoles() throws Exception {
        BigInteger accountId = BigInteger.valueOf(10);
        BigInteger availableRoleId = BigInteger.valueOf(20);
        BigInteger unavailableRoleId = BigInteger.valueOf(30);
        SysAccountRoleService accountRoleService = mock(SysAccountRoleService.class);
        SysAccountRole availableRelation = accountRole(accountId, availableRoleId);
        SysAccountRole unavailableRelation = accountRole(accountId, unavailableRoleId);
        when(accountRoleService.list(any(QueryWrapper.class)))
                .thenReturn(List.of(availableRelation, unavailableRelation));

        SysRole availableRole = role(availableRoleId, EnumDataStatus.AVAILABLE.getCode());
        SysRole unavailableRole = role(unavailableRoleId, EnumDataStatus.UNAVAILABLE.getCode());
        TestSysRoleService service = new TestSysRoleService(List.of(availableRole, unavailableRole));
        setField(service, "sysAccountRoleService", accountRoleService);

        List<SysRole> roles = service.getRolesByAccountId(accountId);

        assertEquals(List.of(availableRole), roles);
    }

    /**
     * 构造账号角色关系。
     *
     * @param accountId 账号 ID
     * @param roleId 角色 ID
     * @return 账号角色关系
     */
    private SysAccountRole accountRole(BigInteger accountId, BigInteger roleId) {
        SysAccountRole relation = new SysAccountRole();
        relation.setAccountId(accountId);
        relation.setRoleId(roleId);
        return relation;
    }

    /**
     * 构造角色。
     *
     * @param roleId 角色 ID
     * @param status 角色状态
     * @return 角色
     */
    private SysRole role(BigInteger roleId, Integer status) {
        SysRole role = new SysRole();
        role.setId(roleId);
        role.setStatus(status);
        return role;
    }

    /**
     * 注入私有字段。
     *
     * @param target 目标对象
     * @param fieldName 字段名称
     * @param value 字段值
     * @throws Exception 字段不存在或无法写入
     */
    private void setField(Object target, String fieldName, Object value) throws Exception {
        Field field = SysRoleServiceImpl.class.getDeclaredField(fieldName);
        field.setAccessible(true);
        field.set(target, value);
    }

    /**
     * 提供固定角色集合的测试服务。
     */
    private static final class TestSysRoleService extends SysRoleServiceImpl {

        private final List<SysRole> roles;

        /**
         * 创建测试服务。
         *
         * @param roles 固定角色集合
         */
        private TestSysRoleService(List<SysRole> roles) {
            this.roles = roles;
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public List<SysRole> listByIds(Collection<? extends Serializable> ids) {
            return roles;
        }
    }
}
