package com.mosquito.project;

import org.flywaydb.core.Flyway;
import org.flywaydb.core.api.output.MigrateResult;
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.stream.Stream;

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

@DisplayName("Flyway 全量迁移冒烟测试（PostgreSQL）")
class FlywayMigrationSmokeTest {

    private PostgreSQLContainer<?> postgres;

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

    @Test
    @DisplayName("空库执行全量迁移应成功且关键表存在")
    void shouldMigrateAllScriptsOnEmptyDatabase() {
        JdbcTemplate jdbcTemplate = migrateOnPostgres();

        Integer roleTableCount = jdbcTemplate.queryForObject(
            "SELECT COUNT(*) FROM information_schema.tables WHERE table_name = 'sys_role'", Integer.class);
        Integer permissionTableCount = jdbcTemplate.queryForObject(
            "SELECT COUNT(*) FROM information_schema.tables WHERE table_name = 'sys_permission'", Integer.class);
        Integer systemConfigTableCount = jdbcTemplate.queryForObject(
            "SELECT COUNT(*) FROM information_schema.tables WHERE table_name = 'system_config'", Integer.class);
        Integer userTagTableCount = jdbcTemplate.queryForObject(
            "SELECT COUNT(*) FROM information_schema.tables WHERE table_name = 'sys_user_tag'", Integer.class);

        assertThat(roleTableCount).isEqualTo(1);
        assertThat(permissionTableCount).isEqualTo(1);
        assertThat(systemConfigTableCount).isEqualTo(1);
        assertThat(userTagTableCount).isEqualTo(1);
    }

    @Test
    @DisplayName("迁移后关键角色应持有新增关键权限")
    void shouldAssignCriticalPermissionsToAdminRoles() {
        JdbcTemplate jdbcTemplate = migrateOnPostgres();

        Integer superAdminCount = 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 ('dashboard.chart.realtime.ALL','dashboard.chart.history.ALL','dashboard.kpi.config.ALL','user.tag.add.ALL','user.tag.view.ALL')",
            Integer.class
        );

        Integer systemAdminCount = 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 ('dashboard.chart.realtime.ALL','dashboard.chart.history.ALL','dashboard.kpi.config.ALL','user.tag.add.ALL','user.tag.view.ALL')",
            Integer.class
        );

        assertThat(superAdminCount).isEqualTo(5);
        assertThat(systemAdminCount).isEqualTo(5);
    }

    @Test
    @DisplayName("迁移后默认admin密码哈希应与admin明文匹配")
    void shouldSeedAdminPasswordHashCorrectly() {
        JdbcTemplate jdbcTemplate = migrateOnPostgres();

        String adminHash = jdbcTemplate.queryForObject(
            "SELECT password_hash FROM sys_user WHERE username = 'admin'",
            String.class
        );

        assertThat(adminHash)
            .isEqualTo("8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918");
    }

    private JdbcTemplate migrateOnPostgres() {
        if (!isContainerRuntimeConfigured()) {
            if (isStrictMigrationMode()) {
                fail("严格模式下未检测到 Docker/Podman socket，禁止跳过 PostgreSQL 迁移验证");
            }
            Assumptions.assumeTrue(false, "未检测到 Docker/Podman socket，跳过 PostgreSQL 迁移验证");
        }

        postgres = new PostgreSQLContainer<>("postgres:15-alpine")
            .withDatabaseName("mosquito_migration_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 flyway = Flyway.configure()
            .dataSource(dataSource)
            .locations("classpath:db/migration")
            .cleanDisabled(true)
            .load();

        MigrateResult result = flyway.migrate();
        assertThat(result.success).isTrue();

        return new JdbcTemplate(dataSource);
    }

    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"));
    }
}
