package de.effigenix.loadtest.infrastructure;

import de.effigenix.EffigenixApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.ConfigurableApplicationContext;
import org.testcontainers.containers.PostgreSQLContainer;

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

/**
 * Startet die komplette Effigenix-Infrastruktur für Lasttests:
 * 1. PostgreSQL via Testcontainers (echtes DB-Verhalten)
 * 2. Spring Boot embedded mit Liquibase-Migrationen
 * 3. Testdaten via LoadTestDataSeeder
 */
public final class LoadTestInfrastructure {

    private static final String POSTGRES_IMAGE = "postgres:16-alpine";
    private static final String DB_NAME = "effigenix_loadtest";
    private static final String DB_USER = "effigenix";
    private static final String DB_PASS = "effigenix";

    private static PostgreSQLContainer<?> postgres;
    private static ConfigurableApplicationContext appContext;
    private static int serverPort;

    private LoadTestInfrastructure() {}

    public static synchronized void start() {
        if (appContext != null) {
            return;
        }

        configureDockerEnvironment();

        postgres = new PostgreSQLContainer<>(POSTGRES_IMAGE)
                .withDatabaseName(DB_NAME)
                .withUsername(DB_USER)
                .withPassword(DB_PASS);
        postgres.start();

        String jdbcUrl = postgres.getJdbcUrl();

        // System-Properties setzen BEVOR Spring startet, damit sie die
        // application.yml-Defaults (${DB_URL:...}) überschreiben.
        System.setProperty("DB_URL", jdbcUrl);
        System.setProperty("DB_USERNAME", DB_USER);
        System.setProperty("DB_PASSWORD", DB_PASS);
        System.setProperty("spring.datasource.url", jdbcUrl);
        System.setProperty("spring.datasource.username", DB_USER);
        System.setProperty("spring.datasource.password", DB_PASS);
        System.setProperty("server.port", "0");

        appContext = new SpringApplicationBuilder(EffigenixApplication.class)
                .properties(
                        "server.port=0",
                        "spring.datasource.url=" + jdbcUrl,
                        "spring.datasource.username=" + DB_USER,
                        "spring.datasource.password=" + DB_PASS,
                        "spring.datasource.driver-class-name=org.postgresql.Driver",
                        "spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect",
                        "spring.jpa.hibernate.ddl-auto=validate",
                        "spring.liquibase.change-log=classpath:db/changelog/db.changelog-master.xml",
                        "spring.liquibase.contexts=dev",
                        "jwt.secret=LoadTestSecretKeyMin256BitsLongForHS256AlgorithmSecurityTest",
                        "jwt.expiration=28800000",
                        "jwt.refresh-expiration=604800000",
                        "effigenix.cors.allowed-origins=*",
                        "logging.level.root=WARN",
                        "logging.level.de.effigenix=INFO",
                        "springdoc.api-docs.enabled=false",
                        "springdoc.swagger-ui.enabled=false",
                        "sentry.dsn="
                )
                .run();

        serverPort = appContext.getEnvironment()
                .getProperty("local.server.port", Integer.class, 8080);

        System.out.println("=== Effigenix ERP gestartet auf Port " + serverPort + " ===");
        System.out.println("=== PostgreSQL: " + jdbcUrl + " ===");

        new LoadTestDataSeeder(appContext).seed();

        System.out.println("=== Testdaten erzeugt ===");
    }

    /**
     * Erkennt die Docker/Podman-Umgebung und konfiguriert Testcontainers entsprechend.
     */
    private static void configureDockerEnvironment() {
        if (System.getenv("DOCKER_HOST") != null) {
            return;
        }
        if (Files.exists(Path.of("/var/run/docker.sock"))) {
            return;
        }

        // Podman rootless Socket
        Path podmanSocket = Path.of("/run/user/" + getUid() + "/podman/podman.sock");
        if (Files.exists(podmanSocket)) {
            System.setProperty("DOCKER_HOST", "unix://" + podmanSocket);
            System.setProperty("TESTCONTAINERS_RYUK_DISABLED", "true");
            System.out.println("=== Podman erkannt: " + podmanSocket + " ===");
            return;
        }

        // Podman root Socket
        Path podmanRootSocket = Path.of("/run/podman/podman.sock");
        if (Files.exists(podmanRootSocket)) {
            System.setProperty("DOCKER_HOST", "unix://" + podmanRootSocket);
            System.setProperty("TESTCONTAINERS_RYUK_DISABLED", "true");
            System.out.println("=== Podman (root) erkannt: " + podmanRootSocket + " ===");
        }
    }

    private static String getUid() {
        try {
            var process = new ProcessBuilder("id", "-u").start();
            return new String(process.getInputStream().readAllBytes()).trim();
        } catch (Exception e) {
            return "1000";
        }
    }

    public static String baseUrl() {
        if (appContext == null) {
            throw new IllegalStateException("LoadTestInfrastructure.start() muss zuerst aufgerufen werden");
        }
        return "http://localhost:" + serverPort;
    }

    public static int port() {
        return serverPort;
    }

    public static synchronized void stop() {
        if (appContext != null) {
            appContext.close();
            appContext = null;
        }
        if (postgres != null) {
            postgres.stop();
            postgres = null;
        }
    }
}
