package db

import (
	"fmt"
	"log"
	"net/url"
	"os"
	"time"

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

var (
	DB *gorm.DB
	// CatalogueDB is a separate connection to the pgvector/catalogue database.
	// It is intentionally isolated from DB (nearledb) so catalogue integration
	// never touches the main database.
	CatalogueDB *gorm.DB
)

// --------------------
// DATABASE CONNECTION
// --------------------

func Connect() {
	dsn := fmt.Sprintf(
		"host=%s user=%s password=%s dbname=%s port=%s sslmode=disable TimeZone=Asia/Kolkata",
		mustEnv("DB_HOST"),
		mustEnv("DB_USER"),
		mustEnv("DB_PASSWORD"),
		mustEnv("DB_NAME"),
		getEnv("DB_PORT", "5433"),
	)

	var err error
	DB, err = gorm.Open(postgres.Open(dsn), &gorm.Config{})
	if err != nil {
		log.Fatal("❌ Could not connect to database:", err)
	}

	setupDB(DB)
	fmt.Println("✅ Database connected")

	connectCatalogueDB()
	connectImageStore()
}

// connectCatalogueDB opens the read-only connection to the catalogue
// (pgvector) database. If its env vars are not set, catalogue endpoints
// are simply unavailable — this must never block startup of the main app.
func connectCatalogueDB() {
	host := getEnv("CATALOGUE_DB_HOST", "")
	if host == "" {
		fmt.Println("⚠️  Catalogue DB env vars not set, skipping catalogue DB connection")
		return
	}

	// Built as a URL (not a keyword=value DSN) and percent-encoded via
	// net/url, because this credential's password contains characters
	// (quotes, #) that the keyword=value DSN format would misparse as
	// quoting/comment syntax.
	dsnURL := url.URL{
		Scheme: "postgres",
		User:   url.UserPassword(mustEnv("CATALOGUE_DB_USER"), mustEnv("CATALOGUE_DB_PASSWORD")),
		Host:   fmt.Sprintf("%s:%s", host, getEnv("CATALOGUE_DB_PORT", "5432")),
		Path:   "/" + mustEnv("CATALOGUE_DB_NAME"),
	}
	q := dsnURL.Query()
	q.Set("sslmode", "disable")
	dsnURL.RawQuery = q.Encode()

	catalogueDB, err := gorm.Open(postgres.Open(dsnURL.String()), &gorm.Config{})
	if err != nil {
		log.Println("❌ Could not connect to catalogue database:", err)
		return
	}

	setupDB(catalogueDB)
	CatalogueDB = catalogueDB
	fmt.Println("✅ Catalogue database connected")
}

func setupDB(database *gorm.DB) {
	sqlDB, err := database.DB()
	if err != nil {
		log.Fatal("❌ Failed to get DB from GORM:", err)
	}
	sqlDB.SetMaxIdleConns(100)
	sqlDB.SetMaxOpenConns(1000)
	sqlDB.SetConnMaxLifetime(time.Minute * 5)
}

// --------------------
// DATABASE SHUTDOWN
// --------------------

func CloseDB() {
	if DB != nil {
		if sqlDB, err := DB.DB(); err == nil {
			sqlDB.Close()
		}
	}
	if CatalogueDB != nil {
		if sqlDB, err := CatalogueDB.DB(); err == nil {
			sqlDB.Close()
		}
	}
	fmt.Println("Connection closed Successfully")
}

// --------------------
// ENV HELPERS
// --------------------

func mustEnv(key string) string {
	val := os.Getenv(key)
	if val == "" {
		log.Fatalf("Missing required env variable: %s", key)
	}
	return val
}

func getEnv(key, fallback string) string {
	if val := os.Getenv(key); val != "" {
		return val
	}
	return fallback
}
