//go:build integration

package nodes_test

import (
	"context"
	"fmt"
	"os"
	"os/exec"
	"testing"
	"time"
)

// TestMain starts a throw-away MySQL 8 Docker container when PANGOLIN_TEST_DSN
// is not already set, runs all tests, and tears the container down on exit.
//
// If Docker is unavailable the tests are skipped gracefully (requireDSN in
// lifecycle_test.go handles the skip).
func TestMain(m *testing.M) {
	if os.Getenv("PANGOLIN_TEST_DSN") != "" {
		// Caller already provided a DSN — run directly.
		os.Exit(m.Run())
	}

	const (
		containerName = "pangolin-lc-test-mysql"
		hostPort      = "13399"
		dbName        = "pangolin_test"
		rootPwd       = "secret"
	)

	ctx := context.Background()

	// Remove any leftover container from a previous crashed run.
	_ = exec.CommandContext(ctx, "docker", "rm", "-f", containerName).Run()

	// Start MySQL 8.
	startCmd := exec.CommandContext(ctx, "docker", "run", "-d",
		"--name", containerName,
		"-e", "MYSQL_ROOT_PASSWORD="+rootPwd,
		"-e", "MYSQL_DATABASE="+dbName,
		"-p", hostPort+":3306",
		"mysql:8",
	)
	if out, err := startCmd.CombinedOutput(); err != nil {
		fmt.Fprintf(os.Stderr, "docker run failed: %v\n%s\n", err, out)
		fmt.Fprintln(os.Stderr, "skipping lifecycle integration tests (no MySQL)")
		os.Exit(0) // graceful skip
	}

	// Tear down on exit regardless of test outcome.
	defer func() {
		_ = exec.Command("docker", "stop", containerName).Run()
		_ = exec.Command("docker", "rm", containerName).Run()
	}()

	// multiStatements=true is required by golang-migrate's MySQL driver so it
	// can execute migration files containing multiple SQL statements in one call.
	// store.Open / buildDSN preserves unrecognised params, so this flag
	// survives the DSN round-trip through buildDSN.
	dsn := fmt.Sprintf("root:%s@tcp(127.0.0.1:%s)/%s?multiStatements=true",
		rootPwd, hostPort, dbName)

	// Wait until MySQL accepts connections (up to 60 s).
	deadline := time.Now().Add(60 * time.Second)
	for time.Now().Before(deadline) {
		ping := exec.CommandContext(ctx, "docker", "exec", containerName,
			"mysqladmin", "ping", "--silent")
		if err := ping.Run(); err == nil {
			break
		}
		time.Sleep(2 * time.Second)
	}

	// Verify connectivity.
	check := exec.CommandContext(ctx, "docker", "exec", containerName,
		"mysqladmin", "ping", "--silent")
	if err := check.Run(); err != nil {
		fmt.Fprintln(os.Stderr, "MySQL did not become ready within 60 s; skipping tests")
		os.Exit(0)
	}

	os.Setenv("PANGOLIN_TEST_DSN", dsn)

	os.Exit(m.Run())
}
