package database

import (
	"context"
	"fmt"
	"sync"
	"time"

	"github.com/jackc/pgx/v5/pgxpool"
)

var (
	pool *pgxpool.Pool
	once sync.Once
	mu   sync.Mutex
)

// GetPool returns the connection pool (singleton)
func GetPool(databaseURL string) (*pgxpool.Pool, error) {
	var err error
	once.Do(func() {
		ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
		defer cancel()

		config, parseErr := pgxpool.ParseConfig(databaseURL)
		if parseErr != nil {
			err = fmt.Errorf("failed to parse database URL: %w", parseErr)
			return
		}

		config.MaxConns = 50
		config.MinConns = 10
		config.MaxConnLifetime = 30 * time.Minute
		config.MaxConnIdleTime = 5 * time.Minute
		config.HealthCheckPeriod = 30 * time.Second

		pool, err = pgxpool.NewWithConfig(ctx, config)
		if err != nil {
			err = fmt.Errorf("failed to create connection pool: %w", err)
			return
		}

		if pingErr := pool.Ping(ctx); pingErr != nil {
			err = fmt.Errorf("failed to ping database: %w", pingErr)
			return
		}
	})

	return pool, err
}

// GetPoolWithDSN allows re-initializing if the DSN changes
func GetPoolWithDSN(databaseURL string) (*pgxpool.Pool, error) {
	mu.Lock()
	defer mu.Unlock()

	if pool != nil {
		pool.Close()
		pool = nil
	}
	once = sync.Once{}

	return GetPool(databaseURL)
}

// Close closes the connection pool
func Close() {
	mu.Lock()
	defer mu.Unlock()

	if pool != nil {
		pool.Close()
		pool = nil
	}
	once = sync.Once{}
}

// HealthCheck verifies the database connection is alive
func HealthCheck() bool {
	ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
	defer cancel()

	if pool == nil {
		return false
	}

	return pool.Ping(ctx) == nil
}
