#!/usr/bin/env node
/**
 * Build the rmfmailto.exe Win11 mailto-handler launcher.
 *
 * Hooked into `npm run build` after tsc + the icon build. Skips work when:
 *   - We're not on Windows (the binary is Win-only; non-Win builds skip).
 *   - The pre-built `bin/rmfmailto.exe` is newer than every source file in
 *     `bin/rmfmailto-src/` (mtime gate — cargo's own incremental cache is
 *     a separate optimization that runs anyway).
 *
 * On a real rebuild, runs `cargo build --release` inside `bin/rmfmailto-src/`
 * and copies `target/release/rmfmailto.exe` to `bin/rmfmailto.exe`. The
 * pre-built binary is checked into git so `npm install -g
 * @bobfrankston/rmfmail` ships it without needing Rust on the install
 * machine — Rust is only required on the BUILD machine.
 */

import fs from "node:fs";
import path from "node:path";
import { execSync, spawnSync } from "node:child_process";
import { fileURLToPath } from "node:url";

const __dirname = path.dirname(fileURLToPath(import.meta.url));
const SRC_DIR = path.join(__dirname, "rmfmailto-src");
const BUILT_EXE = path.join(SRC_DIR, "target", "release", "rmfmailto.exe");
const SHIPPED_EXE = path.join(__dirname, "rmfmailto.exe");

if (process.platform !== "win32") {
    console.log("[rmfmailto] non-Windows host — skipping (binary is Win-only)");
    process.exit(0);
}

// Check cargo availability up-front so a missing toolchain produces a
// clearer message than the spawn error.
try {
    execSync("cargo --version", { stdio: "pipe" });
} catch {
    console.log("[rmfmailto] cargo not found — skipping build (using checked-in bin/rmfmailto.exe).");
    console.log("           Install rustup-init.exe to enable rebuilds when the Rust source changes.");
    process.exit(0);
}

// mtime gate: if the shipped exe is newer than the latest mtime in the src
// tree, skip. Avoids re-invoking cargo on every build when nothing's changed.
function newestMtime(dir) {
    let newest = 0;
    const stack = [dir];
    while (stack.length) {
        const d = stack.pop();
        for (const name of fs.readdirSync(d)) {
            // Skip cargo's own output dir — `target/` mtimes are noise.
            if (name === "target") continue;
            const full = path.join(d, name);
            const st = fs.statSync(full);
            if (st.isDirectory()) stack.push(full);
            else if (st.mtimeMs > newest) newest = st.mtimeMs;
        }
    }
    return newest;
}

const srcMtime = newestMtime(SRC_DIR);
let shippedMtime = 0;
try { shippedMtime = fs.statSync(SHIPPED_EXE).mtimeMs; } catch { /* missing */ }
if (shippedMtime > srcMtime) {
    console.log("[rmfmailto] up-to-date — skipping cargo build");
    process.exit(0);
}

console.log("[rmfmailto] building (cargo --release)...");
const t0 = Date.now();
const r = spawnSync("cargo", ["build", "--release"], {
    cwd: SRC_DIR,
    stdio: "inherit",
    shell: true,
});
if (r.status !== 0) {
    console.error(`[rmfmailto] cargo build failed (exit ${r.status})`);
    process.exit(r.status || 1);
}
fs.copyFileSync(BUILT_EXE, SHIPPED_EXE);
const sec = ((Date.now() - t0) / 1000).toFixed(1);
console.log(`[rmfmailto] built and copied to bin/rmfmailto.exe (${sec}s)`);
