<?php
/**
 * WinRacing Audit Fix Knife 2 — Header Safe Runtime Logger v50.2
 *
 * - Logs warnings/errors without printing them before header()
 * - Starts output buffering safely
 * - API/AJAX/HTML compatible
 * - Does not change AI scoring or decision logic
 */
class ChairmanRuntimeLoggerV502 {
    private static $startedAt = 0.0;
    private static $runId = '';
    private static $logFile = '';
    private static $installed = false;
    private static $bufferStarted = false;

    public static function install($context='runtime', $startBuffer=true) {
        if (self::$installed) return;

        if ($startBuffer && ob_get_level() === 0) {
            ob_start();
            self::$bufferStarted = true;
        }

        self::$installed = true;
        self::$startedAt = microtime(true);
        self::$runId = date('Ymd_His') . '_' . substr(md5(uniqid('', true)), 0, 8);

        $dir = dirname(__DIR__, 2) . '/logs/chairman';
        if (!is_dir($dir)) @mkdir($dir, 0775, true);
        self::$logFile = $dir . '/chairman_' . date('Y-m-d') . '.log';

        set_error_handler(function($severity, $message, $file, $line) use ($context) {
            $suppressed = (error_reporting() === 0);

            ChairmanRuntimeLoggerV502::log('PHP_ERROR', array(
                'context'=>$context,
                'severity'=>$severity,
                'message'=>$message,
                'file'=>$file,
                'line'=>$line,
                'suppressed'=>$suppressed
            ));

            // Fatal errors are still handled by shutdown handler.
            if (in_array($severity, array(E_ERROR,E_PARSE,E_CORE_ERROR,E_COMPILE_ERROR,E_USER_ERROR), true)) {
                return false;
            }

            // Header-safe mode: log non-fatal warnings/notices, do not print them.
            return true;
        });

        set_exception_handler(function($e) use ($context) {
            ChairmanRuntimeLoggerV502::log('UNCAUGHT_EXCEPTION', array(
                'context'=>$context,
                'type'=>get_class($e),
                'message'=>$e->getMessage(),
                'file'=>$e->getFile(),
                'line'=>$e->getLine(),
                'trace'=>$e->getTraceAsString()
            ));

            if (!headers_sent()) http_response_code(500);

            $safeRun = htmlspecialchars(ChairmanRuntimeLoggerV502::runId(), ENT_QUOTES, 'UTF-8');
            echo '<div style="font-family:Arial;padding:18px;background:#160b12;color:#ffdce5;border:1px solid #8f2944">';
            echo '<b>WinRacing runtime error.</b><br>Run ID: '.$safeRun;
            echo '</div>';
        });

        register_shutdown_function(function() use ($context) {
            $last = error_get_last();
            if ($last && in_array($last['type'], array(E_ERROR,E_PARSE,E_CORE_ERROR,E_COMPILE_ERROR,E_USER_ERROR), true)) {
                ChairmanRuntimeLoggerV502::log('FATAL_SHUTDOWN', array(
                    'context'=>$context,
                    'message'=>$last['message'],
                    'file'=>$last['file'],
                    'line'=>$last['line']
                ));
            }

            if (self::$bufferStarted && ob_get_level() > 0) {
                @ob_end_flush();
            }
        });

        self::log('REQUEST_START', array(
            'context'=>$context,
            'method'=>isset($_SERVER['REQUEST_METHOD'])?$_SERVER['REQUEST_METHOD']:'',
            'uri'=>isset($_SERVER['REQUEST_URI'])?$_SERVER['REQUEST_URI']:'',
            'php'=>PHP_VERSION,
            'buffer_level'=>ob_get_level()
        ));
    }

    public static function log($type, array $data=array()) {
        $entry = array(
            'time'=>date('c'),
            'run_id'=>self::$runId,
            'type'=>$type,
            'data'=>$data
        );

        if (self::$logFile !== '') {
            @file_put_contents(
                self::$logFile,
                json_encode($entry, JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES) . PHP_EOL,
                FILE_APPEND|LOCK_EX
            );
        }
    }

    public static function runId() { return self::$runId; }

    public static function executionMs() {
        return self::$startedAt > 0
            ? round((microtime(true)-self::$startedAt)*1000, 2)
            : 0;
    }

    public static function logFile() { return self::$logFile; }
    public static function bufferLevel() { return ob_get_level(); }
    public static function headersSentInfo() {
        $file = '';
        $line = 0;
        $sent = headers_sent($file, $line);
        return array('sent'=>$sent, 'file'=>$file, 'line'=>$line);
    }
}
