<?php
// Save handler for Container Boot & Health settings page.
// Root-only, CSRF-validated POST. Atomically writes to /docker/whp/settings.json.

if (!is_root_user()) { http_response_code(403); echo "Forbidden."; exit; }
if ($_SERVER['REQUEST_METHOD'] !== 'POST') { http_response_code(405); echo "POST required."; exit; }
if (!validate_csrf_token()) { http_response_code(403); echo "CSRF check failed."; exit; }

function clamp_int($val, $min, $max, $default) {
    if (!is_numeric($val)) return $default;
    $i = (int)$val;
    if ($i < $min || $i > $max) return $default;
    return $i;
}

$bo = [
    'enabled'                          => ($_POST['bo_enabled'] ?? '1') === '1',
    'customer_batch_size'              => clamp_int($_POST['bo_batch_size']     ?? 5,   1,  50,  5),
    'customer_batch_delay_sec'         => clamp_int($_POST['bo_batch_delay']    ?? 10,  1,  120, 10),
    'tier_healthcheck_timeout_sec'     => clamp_int($_POST['bo_tier_timeout']   ?? 60,  10, 300, 60),
    'boot_total_timeout_sec'           => clamp_int($_POST['bo_total_timeout']  ?? 600, 60, 1800, 600),
];
$cw = [
    'enabled'                                  => ($_POST['cw_enabled'] ?? '1') === '1',
    'max_restarts_per_tick'                    => clamp_int($_POST['cw_max_per_tick']  ?? 3, 1, 20, 3),
    'settle_window_sec'                        => clamp_int($_POST['cw_settle']        ?? 30, 5, 120, 30),
    'post_start_verify_sec'                    => clamp_int($_POST['cw_verify']        ?? 5,  1, 60,  5),
    'alert_after_consecutive_failures'         => clamp_int($_POST['cw_alert_after']   ?? 5,  2, 20,  5),
];

$path = '/docker/whp/settings.json';
$current = file_exists($path) ? json_decode(file_get_contents($path), true) : [];
if (!is_array($current)) $current = [];
$current['boot_orchestrator'] = $bo;
$current['customer_watchdog'] = $cw;

$tmp = $path . '.tmp.' . getmypid();
$ok = file_put_contents($tmp, json_encode($current, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
if ($ok === false) { http_response_code(500); echo "Could not write settings."; exit; }
// MEDIUM #9: preserve existing permissions; fall back to 0640 when the file
// doesn't exist yet (fileperms() returns false on a missing path).
$perms = @fileperms($path);
@chmod($tmp, ($perms !== false) ? ($perms & 0777) : 0640);
rename($tmp, $path);

// Regenerate the systemd drop-in so boot_total_timeout_sec takes effect on the
// next boot without requiring a manual setup-boot-orchestrator.sh run.
// $timeout_val is a (int)-cast integer — no shell injection risk.
// WHP runs as root so systemctl daemon-reload is safe to call from PHP
// (same pattern used in ssl_manager.php and log_monitor_manager.php).
$timeout_val = (int)$bo['boot_total_timeout_sec'];
if ($timeout_val < 60) $timeout_val = 600;
$drop_in_dir  = '/etc/systemd/system/whp-boot-orchestrator.service.d';
$drop_in_file = $drop_in_dir . '/timeout.conf';
if (!is_dir($drop_in_dir)) {
    @mkdir($drop_in_dir, 0755, true);
}
if (is_dir($drop_in_dir)) {
    $drop_in_content = "[Service]\nTimeoutStartSec={$timeout_val}\n";
    $drop_in_tmp = $drop_in_file . '.tmp.' . getmypid();
    if (@file_put_contents($drop_in_tmp, $drop_in_content) !== false) {
        @chmod($drop_in_tmp, 0644);
        @rename($drop_in_tmp, $drop_in_file);
        // daemon-reload is fast (<200 ms) and is a no-op when systemd is not running
        // (e.g. on the dev machine with no systemd).
        exec('systemctl daemon-reload 2>/dev/null');
    } else {
        error_log('[container-boot-save] could not write systemd drop-in at ' . $drop_in_file);
    }
}

header('Location: /index.php?page=container-boot&saved=1');
exit;
