"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
const globals_1 = require("@jest/globals");
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
const os = __importStar(require("os"));
const database_helper_js_1 = require("../../test-helpers/database-helper.js");
(0, globals_1.describe)('Concurrent Access Tests', () => {
    let tempDir;
    let tempDbPath;
    let dbManager;
    (0, globals_1.beforeEach)(() => {
        tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'mcp-test-'));
        tempDbPath = path.join(tempDir, 'test.db');
        dbManager = database_helper_js_1.TestDatabaseHelper.createTestDatabase();
    });
    (0, globals_1.afterEach)(async () => {
        // Clean up all tracked databases
        await database_helper_js_1.TestDatabaseHelper.cleanupAll();
        // Clean up temp directory
        try {
            fs.rmSync(tempDir, { recursive: true, force: true });
        }
        catch (_error) {
            console.warn('Error cleaning up temp directory:', _error);
        }
        // Clean up any WAL/SHM files
        database_helper_js_1.TestDatabaseHelper.cleanupDbFiles(tempDbPath);
    });
    (0, globals_1.it)('should handle concurrent session writes without corruption', async () => {
        const db = dbManager.getDatabase();
        const sessionId = 'test-session';
        // Create session
        db.prepare(`
      INSERT INTO sessions (id, name, description, branch, working_directory)
      VALUES (?, ?, ?, ?, ?)
    `).run(sessionId, 'Test Session', 'Test', null, null);
        // Simulate concurrent writes to same session
        const promises = [];
        for (let i = 0; i < 10; i++) {
            promises.push(new Promise(resolve => {
                setTimeout(() => {
                    try {
                        db.prepare(`
              INSERT OR REPLACE INTO context_items (id, session_id, key, value, category, priority)
              VALUES (?, ?, ?, ?, ?, ?)
            `).run(`item-${i}`, sessionId, `key-${i}`, `value-${i}`, 'test', 'normal');
                        resolve();
                    }
                    catch (_error) {
                        resolve(); // Still resolve to continue test
                    }
                }, Math.random() * 10);
            }));
        }
        await Promise.all(promises);
        // Verify all items were written
        const items = db
            .prepare('SELECT COUNT(*) as count FROM context_items WHERE session_id = ?')
            .get(sessionId);
        (0, globals_1.expect)(items.count).toBe(10);
    });
    (0, globals_1.it)('should handle concurrent updates to same key', async () => {
        const db = dbManager.getDatabase();
        const sessionId = 'test-session';
        const key = 'shared-key';
        // Create session
        db.prepare(`
      INSERT INTO sessions (id, name, description, branch, working_directory)
      VALUES (?, ?, ?, ?, ?)
    `).run(sessionId, 'Test Session', 'Test', null, null);
        // Initial value
        db.prepare(`
      INSERT INTO context_items (id, session_id, key, value, category, priority)
      VALUES (?, ?, ?, ?, ?, ?)
    `).run('initial', sessionId, key, 'initial-value', 'test', 'normal');
        // Concurrent updates
        const updates = [];
        for (let i = 0; i < 20; i++) {
            updates.push(new Promise(resolve => {
                setTimeout(() => {
                    try {
                        db.prepare(`
              UPDATE context_items 
              SET value = ?, updated_at = CURRENT_TIMESTAMP
              WHERE session_id = ? AND key = ?
            `).run(`value-${i}`, sessionId, key);
                        resolve();
                    }
                    catch (_error) {
                        resolve();
                    }
                }, Math.random() * 10);
            }));
        }
        await Promise.all(updates);
        // Should have exactly one item with the key
        const items = db
            .prepare('SELECT COUNT(*) as count FROM context_items WHERE session_id = ? AND key = ?')
            .get(sessionId, key);
        (0, globals_1.expect)(items.count).toBe(1);
    });
    (0, globals_1.it)('should handle database locks gracefully', () => {
        const db = dbManager.getDatabase();
        // In WAL mode, readers don't block writers and vice versa
        // So we need to test a different scenario - two writers
        // Start a write transaction
        db.prepare('BEGIN IMMEDIATE').run();
        // Try to start another write transaction (should fail)
        let errorThrown = false;
        try {
            // This should fail because we already have a write transaction
            db.prepare('BEGIN IMMEDIATE').run();
        }
        catch (error) {
            errorThrown = true;
            // The exact error code might vary
            (0, globals_1.expect)(error.message).toMatch(/database is locked|cannot start a transaction/i);
        }
        db.prepare('ROLLBACK').run();
        // If no error was thrown, it might be because SQLite is configured differently
        // In that case, just verify we can at least do transactions
        if (!errorThrown) {
            // Verify basic transaction works
            db.prepare('BEGIN').run();
            db.prepare('INSERT INTO sessions (id, name) VALUES (?, ?)').run('test', 'Test');
            db.prepare('COMMIT').run();
            const result = db.prepare('SELECT * FROM sessions WHERE id = ?').get('test');
            (0, globals_1.expect)(result.name).toBe('Test');
        }
    });
    (0, globals_1.it)('should handle WAL mode concurrent reads during write', () => {
        const db = dbManager.getDatabase();
        // Verify WAL mode is enabled
        const journalMode = db.pragma('journal_mode');
        (0, globals_1.expect)(journalMode[0].journal_mode).toBe('wal');
        // Create a session
        const sessionId = 'wal-test';
        db.prepare(`
      INSERT INTO sessions (id, name, description, branch, working_directory)
      VALUES (?, ?, ?, ?, ?)
    `).run(sessionId, 'WAL Test', 'Test', null, null);
        // Start a write transaction
        const writeStmt = db.prepare('BEGIN IMMEDIATE');
        writeStmt.run();
        // Insert item in transaction
        db.prepare(`
      INSERT INTO context_items (id, session_id, key, value, category, priority)
      VALUES (?, ?, ?, ?, ?, ?)
    `).run('item-1', sessionId, 'key-1', 'value-1', 'test', 'normal');
        // Read should work even with ongoing write transaction (WAL mode benefit)
        const readResult = db.prepare('SELECT COUNT(*) as count FROM sessions').get();
        (0, globals_1.expect)(readResult.count).toBeGreaterThan(0);
        // Commit the transaction
        db.prepare('COMMIT').run();
    });
});
