<?php
/**
 * Persistent error logging to the `system_errors` table.
 *
 *   log_error_db('Something failed', 'ingest', ['report_id' => 4]);
 *
 * Also installs PHP exception + shutdown handlers so uncaught exceptions and
 * fatal errors are captured automatically — the SysAdmin Error Log page reads
 * from this table.  Falls back to PHP's error_log() if the DB is unavailable.
 */

if (!function_exists('log_error_db')) {

    function log_error_db(string $message, string $source = 'app', ?array $context = null, string $level = 'error'): void
    {
        try {
            $pdo = db();
            $st  = $pdo->prepare(
                "INSERT INTO system_errors (level, source, message, context, user_id, url, created_at)
                 VALUES (?, ?, ?, ?, ?, ?, NOW())"
            );
            $uid = null;
            if (function_exists('current_user')) {
                try { $u = current_user(); $uid = $u['id'] ?? null; } catch (Throwable $e) {}
            }
            $st->execute([
                mb_substr($level, 0, 16),
                mb_substr($source, 0, 64),
                mb_substr($message, 0, 65000),
                $context ? json_encode($context, JSON_INVALID_UTF8_SUBSTITUTE | JSON_PARTIAL_OUTPUT_ON_ERROR) : null,
                $uid,
                mb_substr((string) ($_SERVER['REQUEST_URI'] ?? ''), 0, 255),
            ]);
        } catch (Throwable $e) {
            // Logger of last resort — never throw from inside the logger.
            @error_log('[medmecs:' . $source . '] ' . $message . '  (logger fallback: ' . $e->getMessage() . ')');
        }
    }

    // Capture any UNCAUGHT exceptions so they appear in the log.  PHP's default
    // behaviour is to print + die; we still want that, so we re-raise via error_log.
    set_exception_handler(function (Throwable $e) {
        log_error_db(
            'Uncaught ' . get_class($e) . ': ' . $e->getMessage() . "\n" . $e->getTraceAsString(),
            'exception'
        );
        @error_log('Uncaught: ' . $e->getMessage());
    });

    // Capture fatal errors at script shutdown (parse errors, OOM, etc.).
    register_shutdown_function(function () {
        $err = error_get_last();
        if (!$err) return;
        if (in_array($err['type'], [E_ERROR, E_PARSE, E_COMPILE_ERROR, E_USER_ERROR, E_CORE_ERROR, E_RECOVERABLE_ERROR], true)) {
            log_error_db(
                'FATAL: ' . $err['message'] . ' in ' . $err['file'] . ':' . $err['line'],
                'fatal'
            );
        }
    });
}
