// Package db gère la connexion à PostgreSQL et l'application des migrations.
package db

import (
	"context"
	"database/sql"
	"fmt"
	"time"

	"github.com/jackc/pgx/v5/pgxpool"
	_ "github.com/jackc/pgx/v5/stdlib" // enregistre le driver database/sql "pgx"
	"github.com/pressly/goose/v3"

	"pdfeditor/migrations"
)

// Connect ouvre un pool de connexions pgx vers la base, en réessayant
// quelques fois pour laisser le temps au service Postgres de démarrer.
func Connect(ctx context.Context, databaseURL string) (*pgxpool.Pool, error) {
	cfg, err := pgxpool.ParseConfig(databaseURL)
	if err != nil {
		return nil, fmt.Errorf("DATABASE_URL invalide : %w", err)
	}

	var pool *pgxpool.Pool
	// On tente plusieurs fois car la base peut ne pas être encore prête au boot.
	for attempt := 1; attempt <= 10; attempt++ {
		pool, err = pgxpool.NewWithConfig(ctx, cfg)
		if err == nil {
			if pingErr := pool.Ping(ctx); pingErr == nil {
				return pool, nil
			} else {
				err = pingErr
				pool.Close()
			}
		}
		time.Sleep(2 * time.Second)
	}
	return nil, fmt.Errorf("connexion à la base impossible après plusieurs tentatives : %w", err)
}

// Migrate applique toutes les migrations embarquées via goose.
// goose s'appuie sur database/sql ; on ouvre une connexion *sql.DB
// à partir de la même configuration pgx le temps de la migration.
func Migrate(databaseURL string) error {
	sqlDB, err := openStdlib(databaseURL)
	if err != nil {
		return fmt.Errorf("ouverture connexion migration : %w", err)
	}
	defer sqlDB.Close()

	goose.SetBaseFS(migrations.FS)
	if err := goose.SetDialect("postgres"); err != nil {
		return fmt.Errorf("dialecte goose : %w", err)
	}
	if err := goose.Up(sqlDB, "."); err != nil {
		return fmt.Errorf("application des migrations : %w", err)
	}
	return nil
}

// openStdlib ouvre une connexion database/sql basée sur le driver pgx stdlib.
func openStdlib(databaseURL string) (*sql.DB, error) {
	return sql.Open("pgx", databaseURL)
}
