/**
 * SQLite Database Connection
 *
 * Manages SQLite database connections using better-sqlite3.
 * Falls back to JSON file storage if SQLite fails.
 *
 * @module persistence/db
 */
import Database from "better-sqlite3";
import { mkdir } from "fs/promises";
import { dirname, join, isAbsolute } from "path";
import { DEFAULT_PERSISTENCE_CONFIG } from "./types.js";
import { MIGRATIONS } from "./migrations/index.js";
import { logger } from "../logger.js";
let dbInstance = null;
let currentDbPath = null;
let isFallbackMode = false;
let lastDbError = null;
export function getDbStatus() {
    return {
        initialized: dbInstance !== null || isFallbackMode,
        isFallbackMode,
        dbPath: currentDbPath,
        error: lastDbError?.message || null,
    };
}
export function isInFallbackMode() {
    return isFallbackMode;
}
export function setFallbackMode(value, error) {
    isFallbackMode = value;
    lastDbError = error || null;
    if (value) {
        logger.warn("persistence.fallback_mode_enabled", {
            error: error?.message,
        });
    }
}
export function getDbPath(projectPath, config) {
    const dbPath = config?.dbPath || DEFAULT_PERSISTENCE_CONFIG.dbPath;
    return isAbsolute(dbPath) ? dbPath : join(projectPath, dbPath);
}
export class DatabaseInitError extends Error {
    cause;
    dbPath;
    constructor(message, cause, dbPath) {
        super(message);
        this.cause = cause;
        this.dbPath = dbPath;
        this.name = "DatabaseInitError";
    }
}
export async function initDatabase(projectPath, config) {
    const fullConfig = { ...DEFAULT_PERSISTENCE_CONFIG, ...config };
    const dbPath = getDbPath(projectPath, fullConfig);
    if (dbInstance && currentDbPath === dbPath) {
        return dbInstance;
    }
    if (dbInstance) {
        dbInstance.close();
        dbInstance = null;
        currentDbPath = null;
    }
    try {
        await mkdir(dirname(dbPath), { recursive: true });
        dbInstance = new Database(dbPath);
        currentDbPath = dbPath;
        if (fullConfig.enableWAL) {
            dbInstance.pragma("journal_mode = WAL");
        }
        if (fullConfig.busyTimeout) {
            dbInstance.pragma(`busy_timeout = ${fullConfig.busyTimeout}`);
        }
        dbInstance.pragma("foreign_keys = ON");
        runMigrations(dbInstance);
        isFallbackMode = false;
        lastDbError = null;
        logger.debug("persistence.db_initialized", { dbPath });
        return dbInstance;
    }
    catch (error) {
        const dbError = new DatabaseInitError(`Failed to initialize SQLite database: ${error instanceof Error ? error.message : String(error)}`, error instanceof Error ? error : undefined, dbPath);
        logger.error("persistence.db_init_failed", {
            dbPath,
            error: dbError.message,
            cause: error instanceof Error ? error.message : String(error),
        });
        setFallbackMode(true, dbError);
        throw dbError;
    }
}
export function getDatabase() {
    return dbInstance;
}
export function closeDatabase() {
    if (dbInstance) {
        dbInstance.close();
        dbInstance = null;
        currentDbPath = null;
    }
}
function runMigrations(db) {
    db.exec(`
    CREATE TABLE IF NOT EXISTS migrations (
      version INTEGER PRIMARY KEY,
      name TEXT NOT NULL,
      applied_at TEXT NOT NULL DEFAULT (datetime('now'))
    )
  `);
    const appliedVersions = new Set(db.prepare("SELECT version FROM migrations").all().map((r) => r.version));
    const sortedMigrations = [...MIGRATIONS].sort((a, b) => a.version - b.version);
    for (const migration of sortedMigrations) {
        if (appliedVersions.has(migration.version)) {
            continue;
        }
        db.transaction(() => {
            db.exec(migration.up);
            db.prepare("INSERT INTO migrations (version, name) VALUES (?, ?)").run(migration.version, migration.name);
        })();
    }
}
export function createInMemoryDatabase() {
    const db = new Database(":memory:");
    db.pragma("foreign_keys = ON");
    runMigrations(db);
    return db;
}
//# sourceMappingURL=db.js.map