import fs from 'fs';
import path from 'path';
import BetterSqlite3 from 'better-sqlite3';
import { initSynapseSchema } from './schema.js';
import { resolveEngineStorageRoot, resolveWorkspaceStateRoot, writeEngineStorageOverride, } from '../../engines/workspace-resolver.js';
function buildSynapsePaths(requestedRoot, storageRoot, fallbackApplied, fallbackReason) {
    const normalizedRequestedRoot = path.resolve(requestedRoot);
    const normalizedStorageRoot = path.resolve(storageRoot);
    const dir = path.join(normalizedStorageRoot, '.synapse');
    return {
        dir,
        ledgerDir: path.join(dir, 'ledger'),
        dbPath: path.join(dir, 'synapse.db'),
        requestedRoot: normalizedRequestedRoot,
        storageRoot: normalizedStorageRoot,
        fallbackApplied,
        fallbackReason,
    };
}
export function resolveSynapsePaths(root) {
    if (typeof root === 'object' && root !== null) {
        const requestedRoot = path.resolve(root.requestedRoot ?? process.cwd());
        const storageRoot = path.resolve(root.storageRoot ?? requestedRoot);
        return buildSynapsePaths(requestedRoot, storageRoot, root.fallbackApplied ?? storageRoot !== requestedRoot, root.fallbackReason);
    }
    const resolution = resolveEngineStorageRoot(typeof root === 'string' ? root : process.cwd(), 'synapse');
    return buildSynapsePaths(resolution.requestedRoot, resolution.storageRoot, resolution.fallbackApplied, resolution.fallbackReason);
}
function openDatabaseAt(paths) {
    fs.mkdirSync(paths.ledgerDir, { recursive: true });
    const db = new BetterSqlite3(paths.dbPath);
    initSynapseSchema(db);
    return db;
}
function quarantineBrokenSynapse(paths) {
    if (!fs.existsSync(paths.dir)) {
        return undefined;
    }
    const stamp = new Date().toISOString().replace(/[:.]/g, '-');
    const quarantinePath = path.join(resolveWorkspaceStateRoot(paths.requestedRoot), 'quarantine', 'synapse', stamp);
    fs.mkdirSync(path.dirname(quarantinePath), { recursive: true });
    fs.cpSync(paths.dir, quarantinePath, { recursive: true, force: true });
    return quarantinePath;
}
export function openSynapseDb(root) {
    const paths = resolveSynapsePaths(root);
    try {
        return {
            db: openDatabaseAt(paths),
            paths,
            degraded: paths.fallbackApplied,
            reason: paths.fallbackReason,
        };
    }
    catch (error) {
        const fallbackStorageRoot = resolveWorkspaceStateRoot(paths.requestedRoot);
        if (path.resolve(paths.storageRoot) === path.resolve(fallbackStorageRoot)) {
            throw error;
        }
        const localReason = error instanceof Error ? error.message : String(error);
        let quarantinePath;
        try {
            quarantinePath = quarantineBrokenSynapse(paths);
        }
        catch {
            quarantinePath = undefined;
        }
        const fallbackReason = [
            `Synapse failed to open ${paths.dbPath}: ${localReason}`,
            `using fallback storage at ${fallbackStorageRoot}`,
            quarantinePath ? `quarantined copy: ${quarantinePath}` : null,
        ].filter(Boolean).join(' · ');
        writeEngineStorageOverride({
            engine: 'synapse',
            requestedRoot: paths.requestedRoot,
            storageRoot: fallbackStorageRoot,
            reason: fallbackReason,
            createdAt: Date.now(),
            quarantinePath,
            sourceDbPath: paths.dbPath,
        });
        const fallbackPaths = resolveSynapsePaths({
            requestedRoot: paths.requestedRoot,
            storageRoot: fallbackStorageRoot,
            fallbackApplied: true,
            fallbackReason,
        });
        return {
            db: openDatabaseAt(fallbackPaths),
            paths: fallbackPaths,
            degraded: true,
            reason: fallbackReason,
            quarantinePath,
        };
    }
}
