package main

import (
	"database/sql"
	"embed"
	"fmt"
	"io/fs"
	"sort"
	"strings"

	_ "github.com/mattn/go-sqlite3"
)

//go:embed migrations/*.sql
var migrationsFS embed.FS

// openDB opens (or creates) the SQLite database and applies migrations.
func openDB(path string) (*sql.DB, error) {
	dsn := fmt.Sprintf("file:%s?_journal=WAL&_foreign_keys=on&_busy_timeout=5000", path)
	conn, err := sql.Open("sqlite3", dsn)
	if err != nil {
		return nil, fmt.Errorf("open: %w", err)
	}
	if err := conn.Ping(); err != nil {
		return nil, fmt.Errorf("ping: %w", err)
	}
	if err := applyMigrations(conn); err != nil {
		conn.Close()
		return nil, fmt.Errorf("migrations: %w", err)
	}
	return conn, nil
}

func applyMigrations(conn *sql.DB) error {
	files, err := fs.Glob(migrationsFS, "migrations/*.sql")
	if err != nil {
		return err
	}
	sort.Strings(files)
	for _, f := range files {
		b, err := migrationsFS.ReadFile(f)
		if err != nil {
			return err
		}
		if _, err := conn.Exec(string(b)); err != nil {
			msg := err.Error()
			// Idempotent ignores for ADD COLUMN re-runs etc.
			if strings.Contains(msg, "duplicate column") ||
				strings.Contains(msg, "already exists") {
				continue
			}
			return fmt.Errorf("%s: %w", f, err)
		}
	}
	return nil
}
