<?php

class ErrorHandler {

    private static array $errorTypeMap = [
        E_ERROR             => 'E_ERROR',
        E_WARNING           => 'E_WARNING',
        E_PARSE             => 'E_PARSE',
        E_NOTICE            => 'E_NOTICE',
        E_CORE_ERROR        => 'E_CORE_ERROR',
        E_CORE_WARNING      => 'E_CORE_WARNING',
        E_COMPILE_ERROR     => 'E_COMPILE_ERROR',
        E_COMPILE_WARNING   => 'E_COMPILE_WARNING',
        E_USER_ERROR        => 'E_USER_ERROR',
        E_USER_WARNING      => 'E_USER_WARNING',
        E_USER_NOTICE       => 'E_USER_NOTICE',
        E_STRICT            => 'E_STRICT',
        E_RECOVERABLE_ERROR => 'E_RECOVERABLE_ERROR',
        E_DEPRECATED        => 'E_DEPRECATED',
        E_USER_DEPRECATED   => 'E_USER_DEPRECATED',
    ];

    private static array $errorTypeLabels = [
        E_ERROR             => 'Fatal Error',
        E_WARNING           => 'Warning',
        E_PARSE             => 'Parse Error',
        E_NOTICE            => 'Notice',
        E_CORE_ERROR        => 'Core Error',
        E_CORE_WARNING      => 'Core Warning',
        E_COMPILE_ERROR     => 'Compile Error',
        E_COMPILE_WARNING   => 'Compile Warning',
        E_USER_ERROR        => 'User Error',
        E_USER_WARNING      => 'User Warning',
        E_USER_NOTICE       => 'User Notice',
        E_STRICT            => 'Strict Standards',
        E_RECOVERABLE_ERROR => 'Recoverable Error',
        E_DEPRECATED        => 'Deprecated',
        E_USER_DEPRECATED   => 'User Deprecated',
    ];

    private static array $fatalTypes = [
        E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR,
        E_USER_ERROR, E_RECOVERABLE_ERROR,
    ];

    public static function handleError($errno, $errstr, $errfile, $errline) {
        if (!(error_reporting() & $errno)) {
            return;
        }

        // Only persist fatal/critical errors — skip warnings, notices, deprecated, strict
        if (in_array($errno, self::$fatalTypes)) {
            self::persistError($errno, $errstr, $errfile, $errline);
            self::logError($errno, $errstr, $errfile, $errline);
        }

        self::displayError($errno, $errstr, $errfile, $errline);

        return true;
    }

    public static function handleException($exception) {
        $trace = $exception->getTraceAsString();
        self::persistError(E_ERROR, $exception->getMessage(), $exception->getFile(), $exception->getLine(), $trace, 'Exception');
        self::logError(E_ERROR, $exception->getMessage(), $exception->getFile(), $exception->getLine());
        self::displayError(E_ERROR, $exception->getMessage(), $exception->getFile(), $exception->getLine(), $trace);
    }

    public static function handleShutdown() {
        $error = error_get_last();
        if ($error !== null && in_array($error['type'], [E_ERROR, E_CORE_ERROR, E_COMPILE_ERROR, E_PARSE])) {
            self::persistError($error['type'], $error['message'], $error['file'], $error['line']);
            self::logError($error['type'], $error['message'], $error['file'], $error['line']);
            self::displayError($error['type'], $error['message'], $error['file'], $error['line']);
        }
    }

    // ─── JSON flat-file persistence ───────────────────────────────────────────

    private static function persistError($errno, $errstr, $errfile, $errline, $trace = null, $forcedType = null) {
        try {
            $errorType = $forcedType ?? (self::$errorTypeMap[$errno] ?? 'UNKNOWN');

            $userId = null;
            $orgId  = null;
            if (isset($_SESSION['login'])) {
                $userId = $_SESSION['login']['userid'] ?? null;
                $orgId  = $_SESSION['login']['org_id']  ?? null;
            }

            $url       = ((!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http')
                       . '://' . ($_SERVER['HTTP_HOST'] ?? '') . ($_SERVER['REQUEST_URI'] ?? '');
            $method    = $_SERVER['REQUEST_METHOD']  ?? null;
            $ipAddress = $_SERVER['REMOTE_ADDR']     ?? null;
            $userAgent = $_SERVER['HTTP_USER_AGENT'] ?? null;
            $referer   = $_SERVER['HTTP_REFERER']    ?? null;

            $entry = [
                'id'         => uniqid('err_', true),
                'userid'     => $userId,
                'org_id'     => $orgId,
                'errortype'  => $errorType,
                'errorcode'  => (string)$errno,
                'url'        => substr($url, 0, 512),
                'file'       => substr($errfile, 0, 512),
                'line'       => (int)$errline,
                'fullerror'  => $errstr,
                'trace'      => $trace,
                'method'     => $method ? substr($method, 0, 10) : null,
                'ip_address' => $ipAddress ? substr($ipAddress, 0, 45) : null,
                'user_agent' => $userAgent ? substr($userAgent, 0, 512) : null,
                'referer'    => $referer ? substr($referer, 0, 512) : null,
                'status'     => 'unresolved',
                'createdate' => date('Y-m-d H:i:s'),
            ];

            $logPath = __DIR__ . '/errors.json';
            $entries = [];
            if (file_exists($logPath)) {
                $raw     = file_get_contents($logPath);
                $decoded = json_decode($raw, true);
                if (is_array($decoded)) {
                    $entries = $decoded;
                }
            }

            array_unshift($entries, $entry);
            if (count($entries) > 1000) {
                $entries = array_slice($entries, 0, 1000);
            }

            file_put_contents($logPath, json_encode($entries, JSON_PRETTY_PRINT), LOCK_EX);

        } catch (\Throwable $e) {
            // Silently fail — never let error logging crash the app
            error_log('ErrorHandler::persistError failed: ' . $e->getMessage());
        }
    }

    // ─── File logging ─────────────────────────────────────────────────────────

    private static function logError($errno, $errstr, $errfile, $errline) {
        $message = date('[Y-m-d H:i:s]') . " Error: [$errno] $errstr in $errfile on line $errline\n";
        error_log($message, 3, __DIR__ . '/app_errors.log');
    }

    // ─── Display (debug mode only) ────────────────────────────────────────────

    private static function displayError($errno, $errstr, $errfile, $errline, $trace = null) {
        $errorType = self::$errorTypeLabels[$errno] ?? 'Unknown Error';

        if (defined('DEBUG') && DEBUG) {
            echo "<div style='background-color:#f8d7da;color:#721c24;padding:10px;margin:10px;border:1px solid #f5c6cb;border-radius:5px;'>";
            echo "<h1 style='color:#721c24;'>" . htmlspecialchars($errorType) . " Occurred</h1>";
            echo "<p><strong>Message:</strong> " . htmlspecialchars($errstr) . "</p>";
            echo "<p><strong>File:</strong> " . htmlspecialchars($errfile) . "</p>";
            echo "<p><strong>Line:</strong> " . htmlspecialchars((string)$errline) . "</p>";
            if ($trace) {
                echo "<h2>Stack Trace:</h2>";
                echo "<pre>" . htmlspecialchars($trace) . "</pre>";
            }
            echo "<h2>Request Details:</h2><pre>";
            echo "URL: "    . htmlspecialchars($_SERVER['REQUEST_URI']    ?? '') . "\n";
            echo "Method: " . htmlspecialchars($_SERVER['REQUEST_METHOD'] ?? '') . "\n";
            echo "Time: "   . date('Y-m-d H:i:s') . "\n";
            echo "IP: "     . htmlspecialchars($_SERVER['REMOTE_ADDR']    ?? '') . "\n";
            echo "</pre></div>";
        }
    }
}
