<?php
/**
 * Global request/response logger, auto-prepended to every PHP request via
 * Apache's php_value auto_prepend_file. Logs to a daily JSON-lines file so
 * we can debug failed player actions after the fact instead of needing to
 * reproduce them live.
 *
 * Captures: request path/method/params (sensitive fields redacted),
 * response body + HTTP code, timing, and any PHP error/exception/fatal
 * that occurs during the request - including fatals, via a shutdown hook.
 */

$__logStart = microtime(true);
$__logDate = date('Y-m-d');
$__logDir = '/var/www/html/data/request_logs';
if (!is_dir($__logDir)) {
    @mkdir($__logDir, 0755, true);
}
$__logFile = $__logDir . '/' . $__logDate . '.jsonl';

$__logErrors = [];

set_error_handler(function ($errno, $errstr, $errfile, $errline) use (&$__logErrors) {
    $__logErrors[] = [
        'type' => 'error',
        'level' => $errno,
        'message' => $errstr,
        'file' => $errfile,
        'line' => $errline,
    ];
    return false; // let PHP's normal handling continue too
});

set_exception_handler(function ($e) use (&$__logErrors) {
    $__logErrors[] = [
        'type' => 'uncaught_exception',
        'class' => get_class($e),
        'message' => $e->getMessage(),
        'file' => $e->getFile(),
        'line' => $e->getLine(),
    ];
});

ob_start();

// Fields that must never be written to the log in plaintext.
$__sensitiveFields = ['password', 'gjp', 'gjp2', 'admin-gjp2', 'newPassword', 'oldPassword'];

function __redactParams($params, $sensitiveFields) {
    $out = [];
    foreach ($params as $k => $v) {
        $out[$k] = in_array($k, $sensitiveFields, true) ? '[redacted]' : $v;
    }
    return $out;
}

register_shutdown_function(function () use ($__logStart, $__logFile, &$__logErrors, $__sensitiveFields) {
    $fatal = error_get_last();
    if ($fatal && in_array($fatal['type'], [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR], true)) {
        $__logErrors[] = [
            'type' => 'fatal',
            'message' => $fatal['message'],
            'file' => $fatal['file'],
            'line' => $fatal['line'],
        ];
    }

    $body = ob_get_contents();
    if (ob_get_level() > 0) ob_end_flush();

    $entry = [
        'time' => date('c'),
        'duration_ms' => round((microtime(true) - $__logStart) * 1000, 2),
        'method' => $_SERVER['REQUEST_METHOD'] ?? '',
        'uri' => $_SERVER['REQUEST_URI'] ?? '',
        'ip' => $_SERVER['REMOTE_ADDR'] ?? '',
        'http_code' => http_response_code() ?: 200,
        'get' => __redactParams($_GET ?? [], $sensitiveFields = ['password', 'gjp', 'gjp2', 'admin-gjp2']),
        'post' => __redactParams($_POST ?? [], ['password', 'gjp', 'gjp2', 'admin-gjp2', 'newPassword', 'oldPassword']),
        'response_body' => mb_substr((string)$body, 0, 2000), // cap so huge level uploads don't bloat the log
        'response_length' => strlen((string)$body),
        'errors' => $__logErrors,
    ];

    @file_put_contents(
        $GLOBALS['__logFile'] ?? $__logFile,
        json_encode($entry, JSON_UNESCAPED_SLASHES) . "\n",
        FILE_APPEND | LOCK_EX
    );
});
