// Smoke-test harness for the Windows VST sandbox path. Loads the addon,
// spawns the sandbox subprocess for Guitar Rig 6, opens its editor, then
// closes and shuts down cleanly. Used by clean-rerun.cmd on the test VM.
//
// Run from the repo root: `node scripts/dev/load-gr6.js > load-gr6-sandbox.log`.
// The Guitar Rig 6 path is hardcoded to its standard Win11 install location;
// adjust the GR6 path below if your install differs.
'use strict';
const path = require('path');
const addonPath = path.join(process.cwd(), 'build', 'Release', 'slopsmith_audio.node');
console.log('[test] loading addon from', addonPath);
const addon = require(addonPath);
console.log('[test] addon loaded; methods:', Object.keys(addon).slice(0, 10).join(', '), '...');

// Global watchdog — best-effort coverage for *asynchronous* hang paths
// (event-loop livelocks, setTimeout-stacked cleanup). loadVST is now a
// Napi::AsyncWorker, so the libuv event loop continues to fire timers
// while the load runs on a worker thread; this watchdog can pre-empt
// a hung async load. addon.shutdown still parks the event loop
// synchronously inside dispatchOnMessageThread, so if shutdown itself
// hangs the timer callback never fires — a proper supervisor-process
// + SIGKILL watchdog belongs in the CI harness (test-suite follow-up).
//
// The timer callback hard-exits — do NOT call addon.shutdown() here,
// it would block on the same dispatchOnMessageThread the addon is
// already stuck in and deadlock the process.
const WATCHDOG_MS = 60000;
const watchdog = setTimeout(() => {
    console.error(`[test] FATAL: watchdog tripped after ${WATCHDOG_MS} ms (async hang)`);
    process.exit(1);
}, WATCHDOG_MS);

function failExit(msg) {
    if (msg) console.log('[test] FAIL:', msg);
    // addon.shutdown blocks on dispatchOnMessageThread (up to 15s) if
    // JUCE init partially succeeded; an init-failure path that triggered
    // *because* the message thread never came up would then time out
    // before the process exits. Cap with a hard process.exit timer so a
    // hung shutdown can't extend the failure window beyond 3s.
    const hardKill = setTimeout(() => {
        console.error('[test] FAIL: addon.shutdown hung, force-exiting');
        process.exit(2);
    }, 3000);
    hardKill.unref();
    try { addon.shutdown(); } catch (_) {}
    try { clearTimeout(watchdog); } catch (_) {}
    try { clearTimeout(hardKill); } catch (_) {}
    process.exit(1);
}

console.log('[test] addon.init()');
try {
    addon.init();
} catch (e) {
    failExit('EXCEPTION on init: ' + e.message);
}

setTimeout(async () => {
    // Allow override for CI / dev machines whose VST3 layout differs from
    // the standard "C:\Program Files\Common Files\VST3" install location.
    // The default Native Instruments install ships "Guitar Rig 6.vst3";
    // some installer versions or FX-only variants land as
    // "Guitar Rig 6 FX.vst3". Try both before giving up.
    const fs = require('fs');
    const candidates = process.env.GR6_PATH
        ? [process.env.GR6_PATH]
        : [
            // NI's own installer drops into a vendor subdir; this is the
            // most common default on a fresh GR6 install.
            'C:\\Program Files\\Native Instruments\\VST3\\Guitar Rig 6.vst3',
            'C:\\Program Files\\Native Instruments\\VST3\\Guitar Rig 6 FX.vst3',
            // Some installs (and the existing CI fixture VM) drop into the
            // shared Common Files VST3 dir; keep these as fallbacks so the
            // existing smoke harness doesn't have to flip overnight.
            'C:\\Program Files\\Common Files\\VST3\\Guitar Rig 6.vst3',
            'C:\\Program Files\\Common Files\\VST3\\Guitar Rig 6 FX.vst3',
          ];
    const gr6 = candidates.find(p => { try { return fs.existsSync(p); } catch (_) { return false; } });
    if (!gr6) {
        console.error('[test] FATAL: no Guitar Rig 6 install found at any of:');
        for (const p of candidates) console.error('  - ' + p);
        console.error('Set GR6_PATH to override (e.g. GR6_PATH="C:\\path\\to\\Guitar Rig 6.vst3" node scripts\\dev\\load-gr6.js).');
        try { addon.shutdown(); } catch (_) {}
        clearTimeout(watchdog);
        process.exit(2);
        return;
    }
    console.log('[test] calling addon.loadVST(' + gr6 + ')');
    let slot;
    try {
        // addon.loadVST is now a Promise<number> (Napi::AsyncWorker); await
        // it. The enclosing setTimeout callback was made async above.
        slot = await addon.loadVST(gr6);
        console.log('[test] loadVST returned slot:', slot);
    } catch (e) {
        failExit('EXCEPTION on loadVST: ' + e.message);
        return;
    }

    if (!Number.isInteger(slot) || slot < 0) {
        failExit('loadVST returned invalid slot: ' + String(slot));
        return;
    }

    setTimeout(() => {
        console.log('[test] calling addon.openPluginEditor(' + slot + ')');
        let ok = false;
        try {
            ok = addon.openPluginEditor(slot);
            console.log('[test] openPluginEditor returned:', ok);
        } catch (e) {
            failExit('EXCEPTION on openPluginEditor: ' + e.message);
            return;
        }
        if (!ok) {
            try { addon.closePluginEditor(slot); } catch (_) {}
            failExit('openPluginEditor returned false');
            return;
        }
        console.log('[test] sleeping 5s for editor creation + potential crash...');
        setTimeout(() => {
            console.log('[test] still alive after editor wait; closing');
            try { addon.closePluginEditor(slot); } catch (e) {}
            try { addon.shutdown(); } catch (e) {}
            clearTimeout(watchdog);
            setTimeout(() => process.exit(0), 1000);
        }, 5000);
    }, 1500);
}, 2000);
