import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
import { dirname } from 'node:path';
import { logger } from '../utils/logger.js';
import { summarizeError } from '../utils/error-display.js';
function isEphemeralDbPath(path) {
    if (!path)
        return true;
    if (path === ':memory:')
        return true;
    return /^file:.*(?:^|[?&])mode=memory(?:&|$)/.test(path);
}
export class SQLiteStore {
    db = null;
    dbPath;
    initPromise = null;
    saveBatchDepth = 0;
    saveDirty = false;
    constructor(dbPath) {
        this.dbPath = dbPath ?? null;
    }
    get isReady() {
        return this.db !== null;
    }
    async init(schema) {
        if (this.db)
            return;
        if (this.initPromise)
            return this.initPromise;
        this.initPromise = this.initialize(schema);
        try {
            await this.initPromise;
        }
        finally {
            this.initPromise = null;
        }
    }
    run(sql, params) {
        this.getDb().run(sql, params);
    }
    exec(sql, params) {
        return this.getDb().exec(sql, params);
    }
    async batch(operation) {
        this.saveBatchDepth += 1;
        try {
            return await operation();
        }
        finally {
            this.saveBatchDepth -= 1;
            if (this.saveBatchDepth === 0 && this.saveDirty) {
                this.saveDirty = false;
                await this.save();
            }
        }
    }
    async save() {
        const dbPath = this.dbPath;
        if (isEphemeralDbPath(dbPath) || !this.db || !dbPath)
            return false;
        if (this.saveBatchDepth > 0) {
            this.saveDirty = true;
            return false;
        }
        try {
            mkdirSync(dirname(dbPath), { recursive: true });
            const data = this.db.export();
            writeFileSync(dbPath, Buffer.from(data));
            logger.debug('SQLiteStore: saved to disk', { path: dbPath });
            return true;
        }
        catch (err) {
            logger.error('SQLiteStore: failed to save', {
                error: summarizeError(err),
            });
            throw err;
        }
    }
    close() {
        if (!this.db)
            return;
        this.db.close();
        this.db = null;
    }
    async initialize(schema) {
        try {
            const initSqlJs = (await import('sql.js')).default;
            const SQL = await initSqlJs();
            const dbPath = this.dbPath;
            if (dbPath && !isEphemeralDbPath(dbPath) && existsSync(dbPath)) {
                this.db = new SQL.Database(readFileSync(dbPath));
                logger.info('SQLiteStore: loaded from disk', { path: dbPath });
            }
            else {
                this.db = new SQL.Database();
                logger.info('SQLiteStore: initialized in-memory');
            }
            schema(this.db);
        }
        catch (err) {
            this.db = null;
            logger.error('SQLiteStore: failed to initialize', {
                error: summarizeError(err),
            });
            throw err;
        }
    }
    getDb() {
        if (!this.db) {
            throw new Error('SQLiteStore: not initialized — call init() first');
        }
        return this.db;
    }
}
