package testutils

import (
	"context"
	"fmt"
	"os"
	"path/filepath"
	"runtime"
	"sort"
	"strings"
	"sync"
	"time"

	"github.com/testcontainers/testcontainers-go"
	"github.com/testcontainers/testcontainers-go/modules/postgres"
	"github.com/testcontainers/testcontainers-go/wait"
)

var (
	pgContainer *postgres.PostgresContainer
	pgDSN       string
	containerOnce sync.Once
	pgErr       error
)

// GetTestContainerDB ensures the postgres container is running and returns the DSN.
// It uses a singleton pattern to start the container only once per test run.
func GetTestContainerDB(ctx context.Context) (string, error) {
	containerOnce.Do(func() {
		pgErr = setupPostgresContainer(ctx)
	})
	return pgDSN, pgErr
}

func setupPostgresContainer(ctx context.Context) error {
	// Find project root relative to this file
	// This file is in internal/testutils/setup.go
	_, filename, _, _ := runtime.Caller(0)
	projectRoot := filepath.Join(filepath.Dir(filename), "../..")
	migrationsDir := filepath.Join(projectRoot, "migrations")

	// Collect migration files
	files, err := os.ReadDir(migrationsDir)
	if err != nil {
		return fmt.Errorf("failed to read migrations dir: %w", err)
	}

	var migrationFiles []string
	for _, f := range files {
		if strings.HasSuffix(f.Name(), ".sql") {
			migrationFiles = append(migrationFiles, filepath.Join(migrationsDir, f.Name()))
		}
	}
	sort.Strings(migrationFiles) // Ensure alphabetical order (001_, 002_, ...)

	// Start Postgres container
	var containerErr error
	pgContainer, containerErr = postgres.Run(ctx,
		"postgres:15-alpine",
		postgres.WithDatabase("veza_test"),
		postgres.WithUsername("veza"),
		postgres.WithPassword("veza"),
		postgres.WithInitScripts(migrationFiles...),
		testcontainers.WithWaitStrategy(
			wait.ForLog("database system is ready to accept connections").
				WithOccurrence(2).
				WithStartupTimeout(60*time.Second)),
	)
	if containerErr != nil {
		return fmt.Errorf("failed to start postgres container: %w", containerErr)
	}

	var dsnErr error
	pgDSN, dsnErr = pgContainer.ConnectionString(ctx, "sslmode=disable")
	if dsnErr != nil {
		return fmt.Errorf("failed to get connection string: %w", dsnErr)
	}

	return nil
}

// TerminateContainer allows manual termination if needed (mostly for cleanup)
func TerminateContainer(ctx context.Context) error {
	if pgContainer != nil {
		return pgContainer.Terminate(ctx)
	}
	return nil
}
