// Package database handles database connections and migrations.
package database

import (
	"database/sql"
	"fmt"

	"github.com/Wikid82/charon/backend/internal/logger"
	"github.com/glebarez/sqlite"
	"gorm.io/gorm"
)

// Connect opens a SQLite database connection with optimized settings.
// Uses WAL mode for better concurrent read/write performance.
func Connect(dbPath string) (*gorm.DB, error) {
	// Open the database connection
	// Note: PRAGMA settings are applied after connection for modernc.org/sqlite compatibility
	db, err := gorm.Open(sqlite.Open(dbPath), &gorm.Config{
		// Skip default transaction for single operations (faster)
		SkipDefaultTransaction: true,
		// Prepare statements for reuse
		PrepareStmt: true,
	})
	if err != nil {
		return nil, fmt.Errorf("open database: %w", err)
	}

	// Configure connection pool
	sqlDB, err := db.DB()
	if err != nil {
		return nil, fmt.Errorf("get underlying db: %w", err)
	}
	configurePool(sqlDB)

	// Set SQLite performance pragmas via SQL execution
	// This is required for modernc.org/sqlite (pure-Go driver) which doesn't
	// support DSN-based pragma parameters like mattn/go-sqlite3
	pragmas := []string{
		"PRAGMA journal_mode=WAL",      // Better concurrent access, faster writes
		"PRAGMA busy_timeout=5000",     // Wait up to 5s instead of failing immediately on lock
		"PRAGMA synchronous=NORMAL",    // Good balance of safety and speed
		"PRAGMA cache_size=-64000",     // 64MB cache for better performance
	}
	for _, pragma := range pragmas {
		if _, err := sqlDB.Exec(pragma); err != nil {
			return nil, fmt.Errorf("failed to execute %s: %w", pragma, err)
		}
	}

	// Verify WAL mode is enabled and log confirmation
	var journalMode string
	if err := db.Raw("PRAGMA journal_mode").Scan(&journalMode).Error; err != nil {
		logger.Log().WithError(err).Warn("Failed to verify SQLite journal mode")
	} else {
		logger.Log().WithField("journal_mode", journalMode).Info("SQLite database connected with optimized settings")
	}

	// Run quick integrity check on startup (non-blocking, warn-only)
	var quickCheckResult string
	if err := db.Raw("PRAGMA quick_check").Scan(&quickCheckResult).Error; err != nil {
		logger.Log().WithError(err).Warn("Failed to run SQLite integrity check on startup")
	} else if quickCheckResult == "ok" {
		logger.Log().Info("SQLite database integrity check passed")
	} else {
		// Database has corruption - log error but don't fail startup
		logger.Log().WithField("quick_check_result", quickCheckResult).
			WithField("error_type", "database_corruption").
			Error("SQLite database integrity check failed - database may be corrupted")
	}

	return db, nil
}

// configurePool sets connection pool settings for SQLite.
// SQLite handles concurrency differently than server databases,
// so we use conservative settings.
func configurePool(sqlDB *sql.DB) {
	// SQLite is file-based, so we limit connections
	// but keep some idle for reuse
	sqlDB.SetMaxOpenConns(1)    // SQLite only allows one writer at a time
	sqlDB.SetMaxIdleConns(1)    // Keep one connection ready
	sqlDB.SetConnMaxLifetime(0) // Don't close idle connections
}
