package com.mosquito.project;

import org.flywaydb.core.Flyway;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assumptions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.testcontainers.containers.PostgreSQLContainer;

import javax.sql.DataSource;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.stream.Stream;

import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.fail;

@DisplayName("角色-权限迁移断言测试")
class RolePermissionMigrationTest {

    private PostgreSQLContainer<?> postgres;

    @AfterEach
    void tearDown() {
        if (postgres != null) {
            postgres.stop();
        }
    }

    @Test
    @DisplayName("super_admin/system_admin 必须拥有关键管理权限")
    void adminRolesShouldContainCriticalPermissions() {
        if (!isContainerRuntimeConfigured()) {
            if (isStrictMigrationMode()) {
                fail("严格模式下未检测到 Docker/Podman socket，禁止跳过 PostgreSQL 角色权限断言");
            }
            Assumptions.assumeTrue(false, "未检测到 Docker/Podman socket，跳过 PostgreSQL 角色权限断言");
        }

        postgres = new PostgreSQLContainer<>("postgres:15-alpine")
            .withDatabaseName("mosquito_role_permission_test")
            .withUsername("mosquito")
            .withPassword("mosquito");
        try {
            postgres.start();
        } catch (Throwable e) {
            if (isStrictMigrationMode()) {
                fail("严格模式下 PostgreSQL 容器启动失败: " + e.getMessage(), e);
            }
            Assumptions.assumeTrue(false, "无法启动 PostgreSQL 容器，跳过测试: " + e.getMessage());
        }

        DataSource dataSource = new DriverManagerDataSource(
            postgres.getJdbcUrl(), postgres.getUsername(), postgres.getPassword());
        Flyway.configure().dataSource(dataSource).locations("classpath:db/migration").load().migrate();

        JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
        List<String> expectedPermissionCodes = List.of(
            "dashboard.chart.realtime.ALL",
            "dashboard.chart.history.ALL",
            "dashboard.kpi.config.ALL",
            "risk.block.execute.ALL",
            "risk.block.release.ALL",
            "user.tag.add.ALL",
            "user.tag.view.ALL",
            "system.api-key.create.ALL",
            "system.api-key.view.ALL",
            "system.api-key.enable.ALL",
            "system.api-key.disable.ALL",
            "system.api-key.delete.ALL",
            "system.api-key.reset.ALL"
        );
        String inClause = expectedPermissionCodes.stream()
            .map(code -> "'" + code + "'")
            .reduce((a, b) -> a + "," + b)
            .orElse("''");

        Integer superAdminPermissionCount = jdbcTemplate.queryForObject(
            "SELECT COUNT(*) " +
                "FROM sys_role_permission rp " +
                "JOIN sys_role r ON r.id = rp.role_id " +
                "JOIN sys_permission p ON p.id = rp.permission_id " +
                "WHERE r.role_code = 'super_admin' AND p.permission_code IN (" + inClause + ")",
            Integer.class
        );

        Integer systemAdminPermissionCount = jdbcTemplate.queryForObject(
            "SELECT COUNT(*) " +
                "FROM sys_role_permission rp " +
                "JOIN sys_role r ON r.id = rp.role_id " +
                "JOIN sys_permission p ON p.id = rp.permission_id " +
                "WHERE r.role_code = 'system_admin' AND p.permission_code IN (" + inClause + ")",
            Integer.class
        );

        assertThat(superAdminPermissionCount).isEqualTo(expectedPermissionCodes.size());
        assertThat(systemAdminPermissionCount).isEqualTo(expectedPermissionCodes.size());
    }

    private boolean isContainerRuntimeConfigured() {
        Path dockerSock = Path.of("/var/run/docker.sock");
        if (Files.exists(dockerSock)) {
            return true;
        }

        Path runUser = Path.of("/run/user");
        if (!Files.isDirectory(runUser)) {
            return false;
        }

        try (Stream<Path> userDirs = Files.list(runUser)) {
            return userDirs.anyMatch(dir -> Files.exists(dir.resolve("podman/podman.sock")));
        } catch (Exception e) {
            return false;
        }
    }

    private boolean isStrictMigrationMode() {
        return Boolean.parseBoolean(System.getProperty("migration.test.strict", "false"))
            || "true".equalsIgnoreCase(System.getenv("STRICT_MIGRATION_TESTS"));
    }

}
