<?php
header('Content-Type: application/json');
require_once dirname(__DIR__) . '/include/scheduler.php';

$id = trim($_POST['id'] ?? '');

if (!$id || !preg_match('/^[a-zA-Z0-9_.\/\-]+\.sh$/', $id) || str_contains($id, '..')) {
    echo json_encode(['ok' => false, 'error' => 'Invalid id']);
    exit;
}

$statFile = vv_job_stat_path($id);
if (!file_exists($statFile)) {
    echo json_encode(['ok' => false, 'error' => 'No stat file — script may not be running']);
    exit;
}

$stat = json_decode(file_get_contents($statFile) ?: '{}', true) ?: [];

if (($stat['status'] ?? '') !== 'running') {
    echo json_encode(['ok' => true, 'msg' => 'Not running']);
    exit;
}

$pid = (int)($stat['pid'] ?? 0);
if ($pid < 2) {
    echo json_encode(['ok' => false, 'error' => 'No valid PID in stat file']);
    exit;
}

// Kill the whole process group so the script and all its children die together.
// pgid is usually the same as the session leader PID from run_job.sh.
$pgid = (int)trim(shell_exec("ps -o pgid= -p $pid 2>/dev/null") ?: '0');

if ($pgid > 1) {
    shell_exec("kill -TERM -$pgid 2>/dev/null");
} else {
    // Fallback: kill the direct PID and its children
    shell_exec("pkill -TERM -P $pid 2>/dev/null");
    shell_exec("kill -TERM $pid 2>/dev/null");
}

// Give it up to 3s to exit gracefully
$dead = false;
for ($i = 0; $i < 6; $i++) {
    usleep(500000);
    if (!file_exists("/proc/$pid")) { $dead = true; break; }
}

// Force-kill if still alive
if (!$dead) {
    if ($pgid > 1) shell_exec("kill -KILL -$pgid 2>/dev/null");
    shell_exec("pkill -KILL -P $pid 2>/dev/null");
    shell_exec("kill -KILL $pid 2>/dev/null");
    usleep(300000);
    $dead = !file_exists("/proc/$pid");
}

// Clear any lock files in /tmp/unraid_locks whose content matches this PID
$lockDir  = '/tmp/unraid_locks';
$cleared  = [];
foreach (glob("$lockDir/*.lock") ?: [] as $lf) {
    $content = trim(file_get_contents($lf) ?: '');
    $lockPid = (int)explode(':', $content)[0];
    if ($lockPid === $pid || !file_exists("/proc/$lockPid")) {
        @unlink($lf);
        $cleared[] = basename($lf);
    }
}

// Also clear by script name in case PID rotated
$scriptBase = basename($id, '.sh');
$namedLock  = "$lockDir/{$scriptBase}.lock";
if (file_exists($namedLock)) {
    @unlink($namedLock);
    if (!in_array(basename($namedLock), $cleared)) $cleared[] = basename($namedLock);
}

// Update stat file — only clear pid if actually dead (D-state processes survive SIGKILL)
$now = time();
$stat['status'] = $dead ? 'stopped' : 'running';
$stat['end']    = $dead ? $now : ($stat['end'] ?? null);
$stat['exit']   = $dead ? -1 : ($stat['exit'] ?? null);
if ($dead) unset($stat['pid']);
file_put_contents($statFile, json_encode($stat));

echo json_encode([
    'ok'      => $dead,
    'killed'  => $dead,
    'locks'   => $cleared,
    'error'   => $dead ? null : 'Process still alive after SIGKILL (D-state) — lock may persist',
]);
