package db

import (
	"fmt"
	"tercul/internal/observability"
	"tercul/internal/platform/config"
	"tercul/internal/platform/log"
	"time"

	"gorm.io/driver/postgres"
	"gorm.io/gorm"
	gormlogger "gorm.io/gorm/logger"
)

// Connect establishes a connection to the database using the provided configuration.
// It returns the database connection and any error encountered.
func Connect(cfg *config.Config, metrics *observability.Metrics) (*gorm.DB, error) {
	log.Info(fmt.Sprintf("Connecting to database: host=%s db=%s", cfg.DBHost, cfg.DBName))

	dsn := fmt.Sprintf("host=%s user=%s password=%s dbname=%s port=%s sslmode=disable",
		cfg.DBHost, cfg.DBUser, cfg.DBPassword, cfg.DBName, cfg.DBPort)

	db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{
		Logger: gormlogger.Default.LogMode(gormlogger.Warn),
	})
	if err != nil {
		return nil, fmt.Errorf("failed to connect to database: %w", err)
	}

	// Register Prometheus plugin
	if err := db.Use(NewPrometheusPlugin(metrics)); err != nil {
		return nil, fmt.Errorf("failed to register prometheus plugin: %w", err)
	}

	// Get the underlying SQL DB instance
	sqlDB, err := db.DB()
	if err != nil {
		return nil, fmt.Errorf("failed to get SQL DB instance: %w", err)
	}

	// Set connection pool settings
	sqlDB.SetMaxOpenConns(20) // Connection pooling
	sqlDB.SetMaxIdleConns(5)  // Idle connections
	sqlDB.SetConnMaxLifetime(30 * time.Minute)

	log.Info(fmt.Sprintf("Successfully connected to database: host=%s db=%s", cfg.DBHost, cfg.DBName))

	return db, nil
}

// Close closes the database connection.
func Close(db *gorm.DB) error {
	if db == nil {
		return nil
	}

	sqlDB, err := db.DB()
	if err != nil {
		return fmt.Errorf("failed to get SQL DB instance: %w", err)
	}

	return sqlDB.Close()
}

// InitDB initializes the database connection.
func InitDB(cfg *config.Config, metrics *observability.Metrics) (*gorm.DB, error) {
	// Connect to the database
	db, err := Connect(cfg, metrics)
	if err != nil {
		return nil, err
	}
	return db, nil
}