package testhelper

import (
	"context"
	"fmt"
	"log/slog"
	"os"
	"time"

	"github.com/golang-migrate/migrate/v4"
	_ "github.com/golang-migrate/migrate/v4/database/postgres"
	_ "github.com/golang-migrate/migrate/v4/source/file"
	"github.com/jackc/pgx/v5/pgxpool"
	"github.com/testcontainers/testcontainers-go"
	"github.com/testcontainers/testcontainers-go/modules/postgres"
	"github.com/testcontainers/testcontainers-go/wait"
)

var (
	container *postgres.PostgresContainer
	dbPool    *pgxpool.Pool
	ctx       = context.Background()
)

// SetupTestDB starts a PostgreSQL container and returns a connection pool
func SetupTestDB() *pgxpool.Pool {
	var err error

	// Start PostgreSQL container
	container, err = postgres.Run(ctx,
		"postgres:16-alpine",
		postgres.WithDatabase("testdb"),
		postgres.WithUsername("postgres"),
		postgres.WithPassword("testpassword"),
		testcontainers.WithWaitStrategy(
			wait.ForLog("database system is ready to accept connections").
				WithOccurrence(2).
				WithStartupTimeout(60*time.Second),
		),
	)
	if err != nil {
		slog.Error("failed to start postgres container", "error", err)
		os.Exit(1)
	}

	// Get connection URL
	host, err := container.Host(ctx)
	if err != nil {
		slog.Error("failed to get container host", "error", err)
		os.Exit(1)
	}

	port, err := container.MappedPort(ctx, "5432")
	if err != nil {
		slog.Error("failed to get container port", "error", err)
		os.Exit(1)
	}

	connectionURL := fmt.Sprintf("postgres://postgres:testpassword@%s:%s/testdb?sslmode=disable",
		host, port.Port())

	// Run migrations
	m, err := migrate.New("file://../../migrations", connectionURL)
	if err != nil {
		slog.Error("failed to create migrate instance", "error", err)
		os.Exit(1)
	}
	defer m.Close()

	if err := m.Up(); err != nil && err != migrate.ErrNoChange {
		slog.Error("failed to run migrations", "error", err)
		os.Exit(1)
	}

	// Create connection pool
	dbPool, err = pgxpool.New(ctx, connectionURL)
	if err != nil {
		slog.Error("failed to create connection pool", "error", err)
		os.Exit(1)
	}

	return dbPool
}

// TeardownTestDB cleans up the test database
func TeardownTestDB() {
	if dbPool != nil {
		dbPool.Close()
	}
	if container != nil {
		if err := container.Terminate(ctx); err != nil {
			slog.Error("failed to terminate container", "error", err)
		}
	}
}
