<?php declare(strict_types=1);
// Christo Lochenberg Developments | info@christodev.co.za | +27 61 523 9126

class ErrorHandler {
    
    /**
     * Initialize the Zero-Breakage global error trap.
     */
    public static function register(): void {
        error_reporting(E_ALL);
        ini_set('display_errors', '0'); // CRITICAL: Never show raw traces to the user
        ini_set('log_errors', '1');
        ini_set('error_log', dirname(__DIR__, 2) . '/logs/error.log');

        set_error_handler([self::class, 'handleError']);
        set_exception_handler([self::class, 'handleException']);
        register_shutdown_function([self::class, 'handleShutdown']);
    }

    /**
     * Convert standard PHP errors into Exceptions so they can be caught by the Exception Handler.
     */
    public static function handleError(int $level, string $message, string $file, int $line): void {
        if (error_reporting() !== 0) { // Respect the @ error suppression operator
            throw new ErrorException($message, 0, $level, $file, $line);
        }
    }

    /**
     * Catch all unhandled Exceptions (including PDO/Database errors).
     */
    public static function handleException(Throwable $exception): void {
        error_log("Uncaught Exception: " . $exception->getMessage() . " in " . $exception->getFile() . " on line " . $exception->getLine());
        
        self::sendCrashReport($exception->getMessage(), $exception->getFile(), $exception->getLine(), $exception->getTraceAsString());
        self::renderErrorPage();
    }

    /**
     * Catch Fatal Errors (e.g., out of memory, syntax errors, calling undefined functions)
     * right before the script completely dies, preventing a blank white screen.
     */
    public static function handleShutdown(): void {
        $error = error_get_last();
        if ($error !== null && in_array($error['type'], [E_ERROR, E_CORE_ERROR, E_COMPILE_ERROR, E_PARSE], true)) {
            error_log("Fatal Error: " . $error['message'] . " in " . $error['file'] . " on line " . $error['line']);
            
            self::sendCrashReport($error['message'], $error['file'], $error['line'], "Fatal Shutdown Error");
            self::renderErrorPage();
        }
    }

    /**
     * Automatically emails a full diagnostic report and error log to the development team.
     */
    private static function sendCrashReport($msg, $file, $line, $trace): void {
        try {
            if (!function_exists('sendEmail')) {
                return; 
            }

            // 1. Gather System Variables
            $settings = function_exists('getSettings') ? getSettings() : [];
            $appName = $settings['app_name'] ?? 'Developer Boilerplate';
            $licenseKey = $settings['license_key'] ?? 'Not Set';
            $dbVersion = $settings['db_version'] ?? 'Unknown';
            
            $appUrl = defined('URLROOT') ? URLROOT : (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? "https" : "http") . "://$_SERVER[HTTP_HOST]";
            $requestUrl = $_SERVER['REQUEST_URI'] ?? 'Unknown URL';
            $currentUser = $_SESSION['user_email'] ?? 'Guest / Unauthenticated';
            
            $phpVersion = phpversion();
            $serverSoft = $_SERVER['SERVER_SOFTWARE'] ?? 'Unknown';
            
            $appVersion = 'Unknown';
            if (defined('APPROOT') && file_exists(APPROOT . '/version.php')) {
                $appVersion = include APPROOT . '/version.php';
            }

            // 2. Safely ping MySQL for version (in case the DB itself is what crashed)
            $mysqlVersion = 'Unknown';
            if (class_exists('Database')) {
                try {
                    $db = new Database();
                    $db->query("SELECT VERSION() as version");
                    $mysqlVersion = $db->single()->version ?? 'Unknown';
                } catch (Throwable $e) {}
            }

            // 3. Construct HTML Email Body
            $body = "<h2 style='color:#dc2626; margin-top:0;'>Critical System Crash (500 Error)</h2>";
            
            $body .= "<h3 style='color:#1f2937; margin-top: 20px; border-bottom: 1px solid #e5e7eb; padding-bottom: 5px;'>System Diagnostics</h3>";
            $body .= "<table style='width: 100%; border-collapse: collapse; font-size: 13px; color: #374151; font-family: sans-serif;'>";
            $body .= "<tr><td style='padding: 6px 0; border-bottom: 1px solid #f3f4f6; width: 150px;'><strong>App Name:</strong></td><td style='padding: 6px 0; border-bottom: 1px solid #f3f4f6;'>{$appName}</td></tr>";
            $body .= "<tr><td style='padding: 6px 0; border-bottom: 1px solid #f3f4f6;'><strong>Live URL:</strong></td><td style='padding: 6px 0; border-bottom: 1px solid #f3f4f6;'><a href='{$appUrl}'>{$appUrl}</a></td></tr>";
            $body .= "<tr><td style='padding: 6px 0; border-bottom: 1px solid #f3f4f6;'><strong>Failed Request URI:</strong></td><td style='padding: 6px 0; border-bottom: 1px solid #f3f4f6;'>{$requestUrl}</td></tr>";
            $body .= "<tr><td style='padding: 6px 0; border-bottom: 1px solid #f3f4f6;'><strong>Active User:</strong></td><td style='padding: 6px 0; border-bottom: 1px solid #f3f4f6;'>{$currentUser}</td></tr>";
            $body .= "<tr><td style='padding: 6px 0; border-bottom: 1px solid #f3f4f6;'><strong>License Key:</strong></td><td style='padding: 6px 0; border-bottom: 1px solid #f3f4f6; font-family: monospace;'>{$licenseKey}</td></tr>";
            $body .= "<tr><td style='padding: 6px 0; border-bottom: 1px solid #f3f4f6;'><strong>App Version:</strong></td><td style='padding: 6px 0; border-bottom: 1px solid #f3f4f6;'>v{$appVersion}</td></tr>";
            $body .= "<tr><td style='padding: 6px 0; border-bottom: 1px solid #f3f4f6;'><strong>DB Version:</strong></td><td style='padding: 6px 0; border-bottom: 1px solid #f3f4f6;'>v{$dbVersion}</td></tr>";
            $body .= "<tr><td style='padding: 6px 0; border-bottom: 1px solid #f3f4f6;'><strong>PHP Version:</strong></td><td style='padding: 6px 0; border-bottom: 1px solid #f3f4f6;'>{$phpVersion}</td></tr>";
            $body .= "<tr><td style='padding: 6px 0; border-bottom: 1px solid #f3f4f6;'><strong>MySQL Version:</strong></td><td style='padding: 6px 0; border-bottom: 1px solid #f3f4f6;'>{$mysqlVersion}</td></tr>";
            $body .= "<tr><td style='padding: 6px 0; border-bottom: 1px solid #f3f4f6;'><strong>Server Software:</strong></td><td style='padding: 6px 0; border-bottom: 1px solid #f3f4f6;'>{$serverSoft}</td></tr>";
            $body .= "</table>";

            $body .= "<h3 style='color:#1f2937; margin-top: 20px;'>Exception Details:</h3>";
            $body .= "<p style='font-family: monospace; background: #f9fafb; padding: 15px; border-radius: 5px; border: 1px solid #fca5a5; color: #dc2626;'>";
            $body .= "<strong>Message:</strong> " . htmlspecialchars((string)$msg) . "<br><br>";
            $body .= "<strong>File:</strong> " . htmlspecialchars((string)$file) . "<br>";
            $body .= "<strong>Line:</strong> " . $line . "</p>";
            
            $body .= "<h3 style='color:#1f2937;'>Stack Trace:</h3>";
            $body .= "<p style='font-family: monospace; background: #f9fafb; padding: 15px; border-radius: 5px; border: 1px solid #e5e7eb; font-size: 12px; color: #4b5563; overflow-x: auto;'>" . nl2br(htmlspecialchars((string)$trace)) . "</p>";

            // 4. Attach the physical error log file if it exists
            $attachments = [];
            $errorLogPath = dirname(__DIR__, 2) . '/logs/error.log'; 
            if (file_exists($errorLogPath)) {
                $attachments[] = $errorLogPath;
            }

            // We use a try/catch here so if the email server is the thing crashing, it doesn't create an infinite loop
            sendEmail('support@christodev.co.za', "CRITICAL CRASH: {$appName}", $body, $attachments);

        } catch (Throwable $e) {
            // Silently fail the email attempt to guarantee the 500 page still shows
            error_log("Failed to send crash report email: " . $e->getMessage());
        }
    }

    /**
     * Render the standalone, self-contained 500 Error HTML page.
     */
    private static function renderErrorPage(): void {
        
        // Wipe the output buffer to remove partially rendered headers/footers
        while (ob_get_level() > 0) {
            ob_end_clean();
        }

        http_response_code(500);
        $errorView = dirname(__DIR__) . '/Views/errors/500.php';
        
        if (file_exists($errorView)) {
            require_once $errorView;
        } else {
            // Ultimate fallback if the view file itself is deleted
            echo "<!DOCTYPE html><html><body style='font-family:sans-serif;text-align:center;padding:50px;'><h1>500 - Internal Server Error</h1><p>Something went wrong. Please try again later.</p></body></html>";
        }
        exit;
    }
}