package machine

import (
	"fmt"
	"os"

	"github.com/jmoiron/sqlx"
	_ "modernc.org/sqlite"
)

const DBFileName = "machine.db"

// NewDB creates a new connection to machine SQLite database and runs schema migrations if necessary.
func NewDB(path string) (*sqlx.DB, error) {
	// Create the database file with 0600 permissions if it doesn't exist, or update permissions if exists.
	if _, err := os.Stat(path); os.IsNotExist(err) {
		file, err := os.OpenFile(path, os.O_CREATE|os.O_RDWR, 0o600)
		if err != nil {
			return nil, fmt.Errorf("create SQLite database '%s': %w", path, err)
		}
		file.Close()
	} else {
		if err = os.Chmod(path, 0o600); err != nil {
			return nil, fmt.Errorf("update SQLite database permissions '%s': %w", path, err)
		}
	}

	// - Write-Ahead Logging (WAL) mode for better read/write performance.
	// - Busy timeout (5s) to make concurrent writes wait on each other instead of failing immediately.
	conn := path + "?_pragma=journal_mode=WAL&_pragma=synchronous=NORMAL&_pragma=busy_timeout=5000&_time_format=sqlite"
	db, err := sqlx.Connect("sqlite", conn)
	if err != nil {
		return nil, fmt.Errorf("connect to SQLite database '%s': %w", conn, err)
	}

	schema := `
	CREATE TABLE IF NOT EXISTS containers (
	    id TEXT NOT NULL PRIMARY KEY,
	    service_spec TEXT NOT NULL CHECK (json_valid(service_spec)),
	    -- 'subsecond' modifier is used to store timestamps with millisecond precision.
	    created_at TIMESTAMP NOT NULL DEFAULT (datetime('subsecond')),
	    updated_at TIMESTAMP NOT NULL DEFAULT (datetime('subsecond'))
	);
    `

	if _, err = db.Exec(schema); err != nil {
		return nil, fmt.Errorf("create schema: %w", err)
	}

	return db, nil
}
