/** Sync-worker ISOLATION test: register real accounts over the bus, run a real
 *  syncAll INSIDE the worker, and prove (a) sync events forward back to main and
 *  (b) the MAIN event loop stays free the whole time. Network-resilient: a sync
 *  failure still validates that the worker didn't take main down with it. */
import fs from "node:fs";
import path from "node:path";
import os from "node:os";
import { spawnSyncWorker } from "../packages/mailx-service/index.js";
import { MailxDB } from "../packages/mailx-store/index.js";
import { loadAccountsAsync } from "../packages/mailx-settings/index.js";

const liveDir = path.join(os.homedir(), ".rmfmail");
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), "rmf-iso-"));
const tmpStore = path.join(tmp, "store");
fs.mkdirSync(tmpStore, { recursive: true });
for (const s of ["", "-wal", "-shm"]) {
    const src = path.join(liveDir, "mailx.db" + s);
    if (fs.existsSync(src)) try { fs.copyFileSync(src, path.join(tmp, "mailx.db" + s)); } catch {}
}
new MailxDB(tmp); // main builds schema first
console.log("\nsync-worker isolation test");

const synced = await spawnSyncWorker({ configDir: tmp, storePath: tmpStore });
console.log("  ✓ worker spawned");

// Register real accounts over the bus.
let accounts = [];
try { accounts = await loadAccountsAsync(); } catch (e) { console.log(`  (loadAccounts failed: ${e.message})`); }
console.log(`  accounts to register: ${accounts.length}`);
for (const a of accounts) {
    try { await synced.proxy.addAccount(a); console.log(`  ✓ addAccount ${a.id} crossed the bus`); }
    catch (e) { console.log(`  ✗ addAccount ${a.id}: ${e.message}`); }
}

// Count sync events forwarded worker → main.
let events = 0;
const seen = new Set();
for (const ev of ["syncProgress", "folderSynced", "syncComplete", "folderCountsChanged", "syncError", "accountError"]) {
    synced.proxy.on(ev, () => { events++; seen.add(ev); });
}

// Main-loop lag monitor: a 25ms heartbeat. If sync in the worker froze main,
// this spikes; if the worker is truly isolated, it stays tiny.
let maxLag = 0, last = Date.now();
const beat = setInterval(() => { const now = Date.now(); maxLag = Math.max(maxLag, now - last - 25); last = now; }, 25);

// Fire a real syncAll in the worker (cap at 25s so a hung network ends the test).
const t0 = Date.now();
console.log("  running syncAll() in the worker (≤25s)…");
await Promise.race([
    synced.proxy.syncAll().catch(e => console.log(`  (syncAll returned error — fine, we're testing isolation: ${String(e.message).slice(0, 60)})`)),
    new Promise(r => setTimeout(r, 25000)),
]);
const elapsed = Date.now() - t0;
clearInterval(beat);

console.log(`\n  syncAll wall time: ${elapsed}ms`);
console.log(`  sync events forwarded to main: ${events}  (${[...seen].join(", ") || "none"})`);
console.log(`  MAIN event-loop max lag during sync: ${maxLag}ms`);

let fail = 0;
if (maxLag < 500) console.log(`  ✓ main loop stayed responsive (maxLag ${maxLag}ms < 500ms) — sync is isolated`);
else { console.log(`  ✗ main loop lagged ${maxLag}ms — sync is NOT isolated`); fail++; }
if (accounts.length === 0) console.log("  ⚠ no accounts loaded — event-forwarding not exercised (network/cloud down)");
else if (events > 0) console.log(`  ✓ real sync events forwarded worker→main`);
else console.log("  ⚠ no sync events seen (network may be down) — isolation still proven by lag");

await synced.close();
try { fs.rmSync(tmp, { recursive: true, force: true }); } catch {}
console.log(`\n${fail ? "RESULT: FAIL" : "RESULT: PASS"}\n`);
process.exit(fail);
