package tech.easyflow.skill.security;

import com.mybatisflex.core.query.QueryWrapper;
import org.junit.Test;
import org.mockito.MockedStatic;
import tech.easyflow.common.entity.LoginAccount;
import tech.easyflow.common.satoken.util.SaTokenUtil;
import tech.easyflow.skill.entity.Skill;
import tech.easyflow.system.entity.vo.RoleCategoryAccessSnapshot;
import tech.easyflow.system.enums.CategoryResourceType;
import tech.easyflow.system.service.CategoryPermissionService;
import tech.easyflow.system.service.SysDeptService;

import java.math.BigInteger;
import java.util.Locale;
import java.util.Set;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.mockStatic;
import static org.mockito.Mockito.when;

/**
 * {@link SkillVisibilityQueryHelper} 的租户边界回归测试。
 */
public class SkillVisibilityQueryHelperTenantTest {

    /**
     * 验证超级管理员的列表查询仍然限定在当前租户内。
     */
    @Test
    public void superAdminQueryShouldStillContainCurrentTenantCondition() {
        CategoryPermissionService categoryPermissionService = mock(CategoryPermissionService.class);
        SysDeptService sysDeptService = mock(SysDeptService.class);
        SkillVisibilityQueryHelper helper = new SkillVisibilityQueryHelper(
                categoryPermissionService, sysDeptService);
        LoginAccount account = account(7, 42);
        when(categoryPermissionService.getCurrentAccess(CategoryResourceType.SKILL.getCode()))
                .thenReturn(new RoleCategoryAccessSnapshot(
                        CategoryResourceType.SKILL.getCode(), account.getId(), true, true, Set.of()));
        QueryWrapper query = QueryWrapper.create().from(Skill.class);

        try (MockedStatic<SaTokenUtil> saToken = mockStatic(SaTokenUtil.class)) {
            saToken.when(SaTokenUtil::getLoginAccount).thenReturn(account);
            helper.applyReadableAccess(query);
        }

        assertTrue("超级管理员查询缺少 tenant_id 条件: " + query.toSQL(),
                query.toSQL().toLowerCase(Locale.ROOT).contains("tenant_id"));
    }

    /**
     * 验证分类 ALL 范围仍按创建人和可见范围过滤，不放行未分类私有 Skill。
     */
    @Test
    public void allCategoryScopeQueryShouldNotBypassPrivateScopeForUnclassifiedSkills() {
        CategoryPermissionService categoryPermissionService = mock(CategoryPermissionService.class);
        SysDeptService sysDeptService = mock(SysDeptService.class);
        SkillVisibilityQueryHelper helper = new SkillVisibilityQueryHelper(
                categoryPermissionService, sysDeptService);
        LoginAccount account = account(7, 42);
        when(categoryPermissionService.getCurrentAccess(CategoryResourceType.SKILL.getCode()))
                .thenReturn(new RoleCategoryAccessSnapshot(
                        CategoryResourceType.SKILL.getCode(), account.getId(), false, true, Set.of()));
        QueryWrapper query = QueryWrapper.create().from(Skill.class);

        try (MockedStatic<SaTokenUtil> saToken = mockStatic(SaTokenUtil.class)) {
            saToken.when(SaTokenUtil::getLoginAccount).thenReturn(account);
            helper.applyReadableAccess(query);
        }

        String sql = query.toSQL().toLowerCase(Locale.ROOT);
        assertTrue("ALL 分类查询缺少创建人边界: " + sql, sql.contains("created_by"));
        assertTrue("ALL 分类查询缺少可见范围边界: " + sql, sql.contains("visibility_scope"));
        assertFalse("ALL 分类查询不应包含未分类越权分支: " + sql,
                sql.contains("category_id") && sql.contains("is null"));
    }

    private LoginAccount account(long accountId, long tenantId) {
        LoginAccount account = new LoginAccount();
        account.setId(BigInteger.valueOf(accountId));
        account.setTenantId(BigInteger.valueOf(tenantId));
        account.setDeptId(BigInteger.valueOf(9));
        return account;
    }
}
