"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.acquireJobLock = acquireJobLock;
exports.releaseJobLock = releaseJobLock;
exports.forceReleaseJobLock = forceReleaseJobLock;
exports.clearStaleLocks = clearStaleLocks;
const node_fs_1 = require("node:fs");
const node_path_1 = require("node:path");
const paths_1 = require("../server/paths");
function locksDir() {
    return (0, node_path_1.join)((0, paths_1.getCockpitDir)(), "job-locks");
}
function lockPath(jobId) {
    return (0, node_path_1.join)(locksDir(), `${jobId}.lock`);
}
function isPidAlive(pid) {
    try {
        process.kill(pid, 0);
        return true;
    }
    catch {
        return false;
    }
}
function readLock(jobId) {
    try {
        return JSON.parse((0, node_fs_1.readFileSync)(lockPath(jobId), "utf-8"));
    }
    catch {
        return null;
    }
}
function acquireJobLock(jobId, runId) {
    (0, node_fs_1.mkdirSync)(locksDir(), { recursive: true });
    const fp = lockPath(jobId);
    const data = { pid: process.pid, runId, acquiredAt: Date.now() };
    try {
        (0, node_fs_1.writeFileSync)(fp, JSON.stringify(data) + "\n", { flag: "wx" });
        return true;
    }
    catch (err) {
        if (err.code !== "EEXIST")
            return false;
    }
    const existing = readLock(jobId);
    if (!existing) {
        try {
            (0, node_fs_1.writeFileSync)(fp, JSON.stringify(data) + "\n", { flag: "wx" });
            return true;
        }
        catch {
            return false;
        }
    }
    if (isPidAlive(existing.pid)) {
        return false;
    }
    console.log(`[scheduler] clearing stale lock for job ${jobId} (pid ${existing.pid} is dead)`);
    try {
        (0, node_fs_1.unlinkSync)(fp);
    }
    catch { }
    try {
        (0, node_fs_1.writeFileSync)(fp, JSON.stringify(data) + "\n", { flag: "wx" });
        return true;
    }
    catch {
        return false;
    }
}
function releaseJobLock(jobId) {
    try {
        const existing = readLock(jobId);
        if (existing && existing.pid === process.pid) {
            (0, node_fs_1.unlinkSync)(lockPath(jobId));
        }
    }
    catch { }
}
function forceReleaseJobLock(jobId) {
    try {
        (0, node_fs_1.unlinkSync)(lockPath(jobId));
    }
    catch { }
}
function clearStaleLocks() {
    if (!(0, node_fs_1.existsSync)(locksDir()))
        return;
    const { readdirSync } = require("node:fs");
    for (const file of readdirSync(locksDir())) {
        if (!file.endsWith(".lock"))
            continue;
        const jobId = file.slice(0, -5);
        const lock = readLock(jobId);
        if (lock && !isPidAlive(lock.pid)) {
            console.log(`[scheduler] removing stale lock for job ${jobId} (pid ${lock.pid})`);
            try {
                (0, node_fs_1.unlinkSync)(lockPath(jobId));
            }
            catch { }
        }
    }
}
