<?php
// ============================================================
// Elegant Work — Manual Cron Runner (Admin + Dev only)
// Runs cron jobs in-process using output buffering.
// No exec() / shell required — works on shared hosting.
// ============================================================
require_once __DIR__ . '/../config/db.php';
require_once __DIR__ . '/../config/auth.php';

$user = requireRole([1, 2]);
$db   = getDB();

$action = post('action', '');
$cron   = post('cron', '');
$force  = post('force', '0') === '1';

$allowed = [
    'send_notifications'  => realpath(__DIR__ . '/../../cron/send_notifications.php'),
    'generate_checklists' => realpath(__DIR__ . '/../../cron/generate_checklists.php'),
    'allocate_leave'      => realpath(__DIR__ . '/../../cron/allocate_leave.php'),
];

if ($action !== 'run')                                       apiError('Invalid action.', 400);
if (!$cron || !isset($allowed[$cron]))                       apiError('Unknown cron job.', 422);
if (!$allowed[$cron] || !file_exists($allowed[$cron]))       apiError('Cron file not found on server.', 500);

// Exception used instead of exit() when running in-process
if (!class_exists('CronExitException')) {
    class CronExitException extends RuntimeException {
        public function __construct(int $code = 0) {
            parent::__construct("exit({$code})", $code);
        }
    }
}

// Force bypass flag for allocate_leave day-of-month guard
if ($force) putenv('EWG_FORCE_CRON=1');

// Signal to cron files they are running inside the app
if (!defined('RUNNING_AS_INCLUDE')) define('RUNNING_AS_INCLUDE', true);
if (!defined('RUNNING_CRON'))       define('RUNNING_CRON', true);

$startTime = microtime(true);
$exitCode  = 0;

ob_start();
try {
    include $allowed[$cron];
} catch (CronExitException $e) {
    $exitCode = $e->getCode();
} catch (Throwable $e) {
    echo "[" . date('Y-m-d H:i:s') . "] FATAL: " . $e->getMessage() . "\n";
    $exitCode = 1;
}
$output = ob_get_clean();

if ($force) putenv('EWG_FORCE_CRON=');

$elapsed = round(microtime(true) - $startTime, 2);

error_log("[EWG Manual Cron] {$cron} run by #{$user['id']} ({$user['username']}) — exit:{$exitCode} in {$elapsed}s");

apiSuccess([
    'cron'      => $cron,
    'exit_code' => $exitCode,
    'elapsed'   => $elapsed,
    'output'    => trim($output) ?: '(no output)',
    'success'   => $exitCode === 0,
], $exitCode === 0 ? 'Cron completed.' : 'Cron finished with errors.');