// Package db provides SQLite database initialization and schema management.
package db

import (
	"database/sql"
	_ "embed"
	"log"
	"os"
	"path/filepath"

	_ "modernc.org/sqlite"
)

//go:embed migrations/001_create_tables.sql
var migration001 string

// DB wraps the sql.DB with connection-level settings.
type DB struct {
	*sql.DB
}

// Open opens the SQLite database at the given path, enables WAL mode,
// and runs all migrations if the tables don't exist yet.
func Open(path string) (*DB, error) {
	// Ensure the directory exists
	dir := filepath.Dir(path)
	if err := os.MkdirAll(dir, 0755); err != nil {
		return nil, err
	}

	db, err := sql.Open("sqlite", path)
	if err != nil {
		return nil, err
	}

	// Enable WAL for concurrent read/write performance
	if _, err := db.Exec("PRAGMA journal_mode=WAL"); err != nil {
		db.Close()
		return nil, err
	}

	// Enable foreign keys
	if _, err := db.Exec("PRAGMA foreign_keys=ON"); err != nil {
		db.Close()
		return nil, err
	}

	// Check if tables already exist (idempotent migration)
	var count int
	if err := db.QueryRow(`
		SELECT COUNT(*) FROM sqlite_master
		WHERE type='table' AND name IN ('cameras', 'status_logs', 'recording_events', 'settings')
	`).Scan(&count); err != nil {
		db.Close()
		return nil, err
	}

	if count < 4 {
		log.Printf("Running migrations for %s...", path)
		if err := migrate(db, migration001); err != nil {
			db.Close()
			return nil, err
		}
		log.Println("Migrations complete")
	}

	return &DB{db}, nil
}

// migrate executes a SQL migration string.
func migrate(db *sql.DB, sql string) error {
	// Split on semicolons to handle multiple statements
	statements := splitSQL(sql)
	for _, stmt := range statements {
		stmt = stripWhitespace(stmt)
		if stmt == "" {
			continue
		}
		if _, err := db.Exec(stmt); err != nil {
			return err
		}
	}
	return nil
}

// splitSQL splits a SQL string on semicolons, respecting quoted strings.
func splitSQL(sql string) []string {
	var stmts []string
	var current string
	inQuote := false
	quoteChar := rune(0)

	for _, r := range sql {
		if inQuote {
			current += string(r)
			if r == quoteChar {
				inQuote = false
			}
			continue
		}
		switch r {
		case '"', '\'', '`':
			inQuote = true
			quoteChar = r
			current += string(r)
		case ';':
			stmts = append(stmts, current)
			current = ""
		default:
			current += string(r)
		}
	}
	if len(current) > 0 {
		stmts = append(stmts, current)
	}
	return stmts
}

// stripWhitespace removes leading/trailing whitespace and normalizes newlines.
func stripWhitespace(s string) string {
	result := ""
	runningSpace := false
	for _, r := range s {
		if r == ' ' || r == '\t' || r == '\n' || r == '\r' {
			if !runningSpace {
				result += " "
				runningSpace = true
			}
		} else {
			result += string(r)
			runningSpace = false
		}
	}
	return result
}
