/** Reproduce the "database is locked" the sync worker hits: two write
 *  connections (main + sync-worker) on one WAL file, hammering concurrent
 *  writes. Tests whether busy_timeout via PRAGMA vs the constructor `timeout`
 *  option actually prevents SQLITE_BUSY under node:sqlite. */
import { DatabaseSync } from "node:sqlite";
import fs from "node:fs";
import path from "node:path";
import os from "node:os";

const tmp = fs.mkdtempSync(path.join(os.tmpdir(), "rmf-2w-"));
const dbPath = path.join(tmp, "t.db");

function setup() {
    const d = new DatabaseSync(dbPath);
    d.exec("PRAGMA journal_mode = WAL");
    d.exec("CREATE TABLE IF NOT EXISTS t (id INTEGER PRIMARY KEY, v TEXT)");
    for (let i = 0; i < 200; i++) d.prepare("INSERT INTO t (id,v) VALUES (?,?)").run(i, "x");
    d.close();
}

// mode: "none" = no busy handling, "pragma" = PRAGMA busy_timeout, "ctor" = constructor timeout
function openWriter(mode, ms) {
    const opts = mode === "ctor" ? { timeout: ms } : {};
    const d = new DatabaseSync(dbPath, opts);
    if (mode === "pragma") d.exec(`PRAGMA busy_timeout = ${ms}`);
    d.exec("PRAGMA foreign_keys = ON");
    return d;
}

async function run(mode, ms) {
    setup();
    const A = openWriter(mode, ms);
    const B = openWriter(mode, ms);
    let locks = 0, ok = 0;
    const hammer = async (d, tag) => {
        for (let i = 0; i < 400; i++) {
            try { d.prepare("UPDATE t SET v=? WHERE id=?").run(`${tag}-${i}`, i % 200); ok++; }
            catch (e) { if (/locked|busy/i.test(e.message)) locks++; else throw e; }
            if (i % 20 === 0) await new Promise(r => setImmediate(r)); // interleave the two
        }
    };
    await Promise.all([hammer(A, "A"), hammer(B, "B")]);
    A.close(); B.close();
    console.log(`  mode=${mode.padEnd(7)} timeout=${ms}ms  → ${ok} ok, ${locks} locked`);
    return locks;
}

console.log("\ntwo-writer lock reproduction (node " + process.version + ")\n");
await run("none", 0);
await run("pragma", 5000);
await run("ctor", 5000);
await run("pragma", 15000);

try { fs.rmSync(tmp, { recursive: true, force: true }); } catch {}
console.log("");
