import { spawnSync } from "node:child_process";
import { resolveGatewayLaunchAgentLabel, resolveGatewaySystemdServiceName, } from "../daemon/constants.js";
const SPAWN_TIMEOUT_MS = 2000;
const SIGUSR1_AUTH_GRACE_MS = 5000;
let sigusr1AuthorizedCount = 0;
let sigusr1AuthorizedUntil = 0;
let sigusr1ExternalAllowed = false;
function resetSigusr1AuthorizationIfExpired(now = Date.now()) {
    if (sigusr1AuthorizedCount <= 0)
        return;
    if (now <= sigusr1AuthorizedUntil)
        return;
    sigusr1AuthorizedCount = 0;
    sigusr1AuthorizedUntil = 0;
}
export function setGatewaySigusr1RestartPolicy(opts) {
    sigusr1ExternalAllowed = opts?.allowExternal === true;
}
export function isGatewaySigusr1RestartExternallyAllowed() {
    return sigusr1ExternalAllowed;
}
export function authorizeGatewaySigusr1Restart(delayMs = 0) {
    const delay = Math.max(0, Math.floor(delayMs));
    const expiresAt = Date.now() + delay + SIGUSR1_AUTH_GRACE_MS;
    sigusr1AuthorizedCount += 1;
    if (expiresAt > sigusr1AuthorizedUntil) {
        sigusr1AuthorizedUntil = expiresAt;
    }
}
export function consumeGatewaySigusr1RestartAuthorization() {
    resetSigusr1AuthorizationIfExpired();
    if (sigusr1AuthorizedCount <= 0)
        return false;
    sigusr1AuthorizedCount -= 1;
    if (sigusr1AuthorizedCount <= 0) {
        sigusr1AuthorizedUntil = 0;
    }
    return true;
}
function formatSpawnDetail(result) {
    const clean = (value) => {
        const text = typeof value === "string" ? value : value ? value.toString() : "";
        return text.replace(/\s+/g, " ").trim();
    };
    if (result.error) {
        if (result.error instanceof Error)
            return result.error.message;
        if (typeof result.error === "string")
            return result.error;
        try {
            return JSON.stringify(result.error);
        }
        catch {
            return "unknown error";
        }
    }
    const stderr = clean(result.stderr);
    if (stderr)
        return stderr;
    const stdout = clean(result.stdout);
    if (stdout)
        return stdout;
    if (typeof result.status === "number")
        return `exit ${result.status}`;
    return "unknown error";
}
function normalizeSystemdUnit(raw, profile) {
    const unit = raw?.trim();
    if (!unit) {
        return `${resolveGatewaySystemdServiceName(profile)}.service`;
    }
    return unit.endsWith(".service") ? unit : `${unit}.service`;
}
export function triggerClawdbotRestart() {
    if (process.env.VITEST || process.env.NODE_ENV === "test") {
        return { ok: true, method: "supervisor", detail: "test mode" };
    }
    const tried = [];
    if (process.platform !== "darwin") {
        if (process.platform === "linux") {
            const unit = normalizeSystemdUnit(process.env.OPENCLAW_SYSTEMD_UNIT, process.env.OPENCLAW_PROFILE);
            const userArgs = ["--user", "restart", unit];
            tried.push(`systemctl ${userArgs.join(" ")}`);
            const userRestart = spawnSync("systemctl", userArgs, {
                encoding: "utf8",
                timeout: SPAWN_TIMEOUT_MS,
            });
            if (!userRestart.error && userRestart.status === 0) {
                return { ok: true, method: "systemd", tried };
            }
            const systemArgs = ["restart", unit];
            tried.push(`systemctl ${systemArgs.join(" ")}`);
            const systemRestart = spawnSync("systemctl", systemArgs, {
                encoding: "utf8",
                timeout: SPAWN_TIMEOUT_MS,
            });
            if (!systemRestart.error && systemRestart.status === 0) {
                return { ok: true, method: "systemd", tried };
            }
            const detail = [
                `user: ${formatSpawnDetail(userRestart)}`,
                `system: ${formatSpawnDetail(systemRestart)}`,
            ].join("; ");
            return { ok: false, method: "systemd", detail, tried };
        }
        return {
            ok: false,
            method: "supervisor",
            detail: "unsupported platform restart",
        };
    }
    const label = process.env.OPENCLAW_LAUNCHD_LABEL ||
        resolveGatewayLaunchAgentLabel(process.env.OPENCLAW_PROFILE);
    const uid = typeof process.getuid === "function" ? process.getuid() : undefined;
    const target = uid !== undefined ? `gui/${uid}/${label}` : label;
    const args = ["kickstart", "-k", target];
    tried.push(`launchctl ${args.join(" ")}`);
    const res = spawnSync("launchctl", args, {
        encoding: "utf8",
        timeout: SPAWN_TIMEOUT_MS,
    });
    if (!res.error && res.status === 0) {
        return { ok: true, method: "launchctl", tried };
    }
    return {
        ok: false,
        method: "launchctl",
        detail: formatSpawnDetail(res),
        tried,
    };
}
export function scheduleGatewaySigusr1Restart(opts) {
    const delayMsRaw = typeof opts?.delayMs === "number" && Number.isFinite(opts.delayMs)
        ? Math.floor(opts.delayMs)
        : 2000;
    const delayMs = Math.min(Math.max(delayMsRaw, 0), 60_000);
    const reason = typeof opts?.reason === "string" && opts.reason.trim()
        ? opts.reason.trim().slice(0, 200)
        : undefined;
    authorizeGatewaySigusr1Restart(delayMs);
    const pid = process.pid;
    const hasListener = process.listenerCount("SIGUSR1") > 0;
    setTimeout(() => {
        try {
            if (hasListener) {
                process.emit("SIGUSR1");
            }
            else {
                process.kill(pid, "SIGUSR1");
            }
        }
        catch {
            /* ignore */
        }
    }, delayMs);
    return {
        ok: true,
        pid,
        signal: "SIGUSR1",
        delayMs,
        reason,
        mode: hasListener ? "emit" : "signal",
    };
}
export const __testing = {
    resetSigusr1State() {
        sigusr1AuthorizedCount = 0;
        sigusr1AuthorizedUntil = 0;
        sigusr1ExternalAllowed = false;
    },
};
