package database

import (
	"database/sql"
	"fmt"
	"log"
	"os"
	"strings"

	_ "github.com/lib/pq"
)

var DB *sql.DB

func InitDB() {
	var err error
	connStr, err := BuildConnectionString()
	if err != nil {
		log.Fatalf("Configuration error: %v", err)
	}

	DB, err = sql.Open("postgres", connStr)
	if err != nil {
		log.Fatalf("Error opening database: %v", err)
	}

	if err = DB.Ping(); err != nil {
		log.Fatalf("Error connecting to database: %v", err)
	}

	log.Println("✅ Successfully connected to the database")
}

func BuildConnectionString() (string, error) {
	// Prefer DATABASE_URL if set (standard format)
	if dbURL := os.Getenv("DATABASE_URL"); dbURL != "" {
		log.Println("Using DATABASE_URL for connection")
		return dbURL, nil
	}

	// Fallback to individual params for backward compatibility
	host := os.Getenv("DB_HOST")
	if host == "" {
		return "", fmt.Errorf("DATABASE_URL or DB_HOST environment variable not set")
	}
	user := os.Getenv("DB_USER")
	if user == "" {
		return "", fmt.Errorf("DB_USER environment variable not set")
	}
	password := os.Getenv("DB_PASSWORD")
	if password == "" {
		return "", fmt.Errorf("DB_PASSWORD environment variable not set")
	}
	dbname := os.Getenv("DB_NAME")
	if dbname == "" {
		return "", fmt.Errorf("DB_NAME environment variable not set")
	}
	port := os.Getenv("DB_PORT")
	if port == "" {
		port = "5432"
	}

	sslmode := os.Getenv("DB_SSLMODE")
	if sslmode == "" {
		sslmode = "require" // Default to require for production security
	}

	connStr := fmt.Sprintf("host=%s port=%s user=%s password=%s dbname=%s sslmode=%s",
		host, port, user, password, dbname, sslmode)
	log.Println("Using individual DB_* params for connection")
	return connStr, nil

}

func RunMigrations() {
	files, err := os.ReadDir("migrations")
	if err != nil {
		// Try fallback to relative path if running from cmd/api
		files, err = os.ReadDir("../../migrations")
		if err != nil {
			log.Printf("⚠️  Warning: Could not list migrations directory: %v", err)
			return
		}
	}

	// Sort files by name to ensure order (001, 002, ...)
	// ReadDir returns sorted by name automatically, but let's be safe if logic changes?
	// Actually ReadDir result is sorted by filename.

	for _, file := range files {
		if file.IsDir() {
			continue
		}

		log.Printf("📦 Running migration: %s", file.Name())
		content, err := os.ReadFile("migrations/" + file.Name())
		if err != nil {
			// Try fallback
			content, err = os.ReadFile("../../migrations/" + file.Name())
			if err != nil {
				log.Fatalf("❌ Error reading migration file %s: %v", file.Name(), err)
			}
		}

		_, err = DB.Exec(string(content))
		if err != nil {
			errStr := err.Error()
			// Check if it's an "already exists" error - these are safe to skip
			if strings.Contains(errStr, "already exists") {
				log.Printf("⏭️  Migration %s skipped (already applied)", file.Name())
			} else {
				// Real error - log it
				log.Printf("❌ Error running migration %s: %v", file.Name(), err)
			}
		} else {
			log.Printf("✅ Migration %s executed successfully", file.Name())
		}
	}
	log.Println("All migrations processed")
}
