// Shared SQLite helper — fail-soft DB initialization with the same
// `getDb()` + `dbBroken` pattern previously copied across audit-log,
// job-board, and schedule. Centralizing it makes the bun-degraded
// behavior consistent and one-place-to-fix.
import Database from 'better-sqlite3';
import { mkdirSync } from 'node:fs';
import { dirname } from 'node:path';
/**
 * Create an opener that lazily initializes the DB on first call. If the
 * native module can't be loaded (bun runtime, missing libstdc++) or any
 * step throws, the helper transitions to "broken" and every subsequent
 * `get()` returns null — letting callers fail soft without crashing the
 * pipeline.
 */
export function createSqliteHelper(opts) {
    let db = null;
    let dbBroken = false;
    const log = opts.logger?.child({ component: opts.component || 'sqlite' });
    return {
        get() {
            if (dbBroken)
                return null;
            if (!db) {
                try {
                    mkdirSync(dirname(opts.file), { recursive: true });
                    db = new Database(opts.file);
                    db.pragma('journal_mode = WAL');
                    db.pragma('synchronous = NORMAL');
                    db.exec(opts.schema);
                    if (opts.init)
                        opts.init(db);
                }
                catch (err) {
                    dbBroken = true;
                    db = null;
                    const msg = err instanceof Error ? err.message : String(err);
                    log?.warn({ event: 'sqlite.disabled', file: opts.file, error: msg }, `${opts.component || 'sqlite'} disabled: ${msg}`);
                    return null;
                }
            }
            return db;
        },
        safe(fn, fallback) {
            const d = this.get();
            if (!d)
                return fallback;
            try {
                return fn(d);
            }
            catch (err) {
                log?.warn({ event: 'sqlite.query.failed', error: err instanceof Error ? err.message : String(err) }, 'SQLite query failed');
                return fallback;
            }
        },
        close() {
            if (!db)
                return;
            try {
                // better-sqlite3 .close() does an implicit WAL checkpoint and
                // releases the file handles — no async, throws synchronously on
                // double-close (we guard with the null check above).
                db.close();
                log?.info({ event: 'sqlite.closed', file: opts.file });
            }
            catch (err) {
                log?.warn({ event: 'sqlite.close.failed', error: err instanceof Error ? err.message : String(err) });
            }
            finally {
                db = null;
            }
        },
        _markBroken(reason) {
            dbBroken = true;
            db = null;
            log?.warn({ event: 'sqlite.markbroken', reason }, `marked broken: ${reason}`);
        },
    };
}
//# sourceMappingURL=sqlite-helper.js.map