/** Daemon-boot integration: construct the FULL MailxService with the sync
 *  proxy + read-worker exactly as bin/mailx.ts does, then verify reads work and
 *  nothing crashes while the reconciler's timers fire. Catches boot wiring bugs
 *  the component tests can't (service ↔ proxy ↔ reconciler interplay). */
import fs from "node:fs";
import path from "node:path";
import os from "node:os";
import { spawnSyncWorker, MailxService } from "../packages/mailx-service/index.js";
import { MailxDB, Store, FileMessageStore } from "../packages/mailx-store/index.js";

const liveDir = path.join(os.homedir(), ".rmfmail");
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), "rmf-boot-"));
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 {}
}
let fail = 0;
const ok = (m) => console.log("  ✓", m);
const bad = (m) => { console.error("  ✗", m); fail++; };
process.on("uncaughtException", (e) => bad(`uncaughtException: ${e.message}`));
process.on("unhandledRejection", (e) => bad(`unhandledRejection: ${e?.message || e}`));

console.log("\nservice-boot integration test");

// Mirror bin/mailx.ts: store on main, sync worker, MailxService(store, proxy).
const db = new MailxDB(tmp);
const store = new Store(db, new FileMessageStore(tmpStore));
const synced = await spawnSyncWorker({ configDir: tmp, storePath: tmpStore });
ok("sync worker spawned");

let svc;
try { svc = new MailxService(store, synced.proxy); ok("MailxService constructed with proxy (no throw)"); }
catch (e) { bad(`MailxService ctor threw: ${e.message}`); process.exit(1); }

// Give the read-worker a moment to come up, then exercise reads.
await new Promise(r => setTimeout(r, 400));
try {
    const accts = await svc.getAccounts();
    ok(`getAccounts() → ${accts.length} accounts`);
} catch (e) { bad(`getAccounts threw: ${e.message}`); }
try {
    const inbox = await svc.getUnifiedInbox(1, 20, false);
    ok(`getUnifiedInbox() → ${inbox.items.length} items / total ${inbox.total}`);
    if (inbox.items[0] && !inbox.items[0].uuid) bad("envelope missing uuid (highlight regression)");
} catch (e) { bad(`getUnifiedInbox threw: ${e.message}`); }
try {
    const ob = await svc.getOutboxStatus();
    ok(`getOutboxStatus() (via worker) → total ${ob.total}`);
} catch (e) { bad(`getOutboxStatus threw: ${e.message}`); }

// Let the reconciler's startup timers fire — this is where a proxy/await
// mismatch would blow up. Watch for ~6s.
console.log("  letting reconciler timers run for 6s (watching for crashes)…");
await new Promise(r => setTimeout(r, 6000));
ok("survived 6s of reconciler activity without crashing");

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