package tech.easyflow.skill.mapper;

import org.junit.Test;

import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

/**
 * Skill 操作权限迁移的最小授权与升级兼容契约测试。
 */
public class SkillPermissionMigrationContractTest {

    /**
     * 验证 V28 只向超级管理员角色授予新增权限，不扩大其他角色权限。
     *
     * @throws Exception 读取迁移文件失败
     */
    @Test
    public void operationPermissionsShouldDefaultToSuperAdminOnly() throws Exception {
        String sql = migrationSql("V28__mysql_skill_operation_permissions.sql");
        int roleGrantStart = sql.indexOf("INSERT INTO `tb_sys_role_menu`");
        String roleGrants = sql.substring(roleGrantStart);

        assertTrue(roleGrantStart > 0);
        assertEquals(5, occurrences(roleGrants, "`role_id` = 1"));
        assertFalse(roleGrants.contains("FROM `tb_sys_role`"));
        assertFalse(roleGrants.contains("SELECT `id` FROM `tb_sys_role`"));
    }

    /**
     * 验证 V29 先保留历史角色授权，再删除无真实入口的旧菜单。
     *
     * @throws Exception 读取迁移文件失败
     */
    @Test
    public void deletePermissionCleanupShouldPreserveExplicitRoleGrants() throws Exception {
        String sql = migrationSql("V29__mysql_skill_delete_permission_cleanup.sql");
        int duplicateCleanup = sql.indexOf("DELETE legacy_mapping");
        int grantMigration = sql.indexOf("UPDATE `tb_sys_role_menu`");
        int deadMenuCleanup = sql.indexOf("DELETE FROM `tb_sys_menu`");

        assertTrue(duplicateCleanup >= 0);
        assertTrue(grantMigration > duplicateCleanup);
        assertTrue(deadMenuCleanup > grantMigration);
        assertTrue(sql.contains("SET `menu_id` = 367400000000000018"));
        assertTrue(sql.contains("WHERE `menu_id` = 367400000000000015"));
        assertTrue(sql.contains("`permission_tag` = '/api/v1/skill/remove'"));
        assertTrue(sql.contains("`permission_tag` = '/api/v1/skill/submitDeleteApproval'"));
        assertFalse(sql.contains("INSERT INTO `tb_sys_role_menu`"));
    }

    /**
     * 统计文本片段出现次数。
     *
     * @param source 原始文本
     * @param target 目标片段
     * @return 出现次数
     */
    private int occurrences(String source, String target) {
        int count = 0;
        int index = 0;
        while ((index = source.indexOf(target, index)) >= 0) {
            count++;
            index += target.length();
        }
        return count;
    }

    /**
     * 读取指定 MySQL 迁移。
     *
     * @param fileName 迁移文件名
     * @return 迁移 SQL
     * @throws Exception 迁移文件不存在或不可读
     */
    private String migrationSql(String fileName) throws Exception {
        Path root = Path.of(System.getProperty("maven.multiModuleProjectDirectory",
                Path.of(System.getProperty("user.dir")).toAbsolutePath().toString()));
        while (root != null) {
            Path migration = root.resolve("easyflow-starter/easyflow-starter-all/src/main/resources/"
                    + "db/migration/mysql/" + fileName);
            if (Files.isRegularFile(migration)) {
                return Files.readString(migration, StandardCharsets.UTF_8);
            }
            root = root.getParent();
        }
        throw new IllegalStateException("未找到 Skill MySQL 迁移文件: " + fileName);
    }
}
