<?php

/**
 * ErrorHandler - Centralized error handling and logging system
 * Provides consistent error handling across the application
 */
class ErrorHandler
{
    private static $logDir = 'system/cache/logs/';
    private static $errorLog = 'errors.log';
    private static $accessLog = 'access.log';
    private static $maxLogSize = 5242880; // 5MB
    
    /**
     * Initialize error handler
     */
    public static function init()
    {
        // Create log directory if it doesn't exist
        if (!is_dir(self::$logDir)) {
            @mkdir(self::$logDir, 0755, true);
        }
        
        // Set custom error and exception handlers
        set_error_handler([self::class, 'handleError']);
        set_exception_handler([self::class, 'handleException']);
        register_shutdown_function([self::class, 'handleShutdown']);
    }
    
    /**
     * Log message with level
     * 
     * @param string $level ERROR, WARNING, INFO, DEBUG, CRITICAL
     * @param string $message Message to log
     * @param array $context Additional context
     */
    public static function log($level, $message, $context = [])
    {
        global $_app_stage;
        
        $timestamp = date('Y-m-d H:i:s');
        $ip = self::getClientIP();
        $url = $_SERVER['REQUEST_URI'] ?? 'CLI';
        
        // Format context
        $contextStr = !empty($context) ? ' | Context: ' . json_encode($context, JSON_UNESCAPED_SLASHES) : '';
        
        // Build log message
        $logMessage = sprintf(
            "[%s] %s | IP: %s | URL: %s | %s%s\n",
            $timestamp,
            $level,
            $ip,
            $url,
            $message,
            $contextStr
        );
        
        // Write to log file
        $logFile = self::$logDir . self::$errorLog;
        self::writeLog($logFile, $logMessage);
        
        // Send critical alerts
        if ($level === 'CRITICAL' && isset($_app_stage) && $_app_stage === 'Live') {
            self::notifyAdmin($message, $context);
        }
        
        // Display in development mode
        if (isset($_app_stage) && $_app_stage !== 'Live' && $level === 'ERROR') {
            error_log($logMessage);
        }
    }
    
    /**
     * Handle PHP errors
     */
    public static function handleError($errno, $errstr, $errfile, $errline)
    {
        // Don't log suppressed errors (@)
        if (!(error_reporting() & $errno)) {
            return false;
        }
        
        $levelMap = [
            E_ERROR => 'ERROR',
            E_WARNING => 'WARNING',
            E_PARSE => 'ERROR',
            E_NOTICE => 'INFO',
            E_CORE_ERROR => 'CRITICAL',
            E_CORE_WARNING => 'WARNING',
            E_COMPILE_ERROR => 'CRITICAL',
            E_COMPILE_WARNING => 'WARNING',
            E_USER_ERROR => 'ERROR',
            E_USER_WARNING => 'WARNING',
            E_USER_NOTICE => 'INFO',
            E_STRICT => 'INFO',
            E_RECOVERABLE_ERROR => 'ERROR',
            E_DEPRECATED => 'INFO',
            E_USER_DEPRECATED => 'INFO'
        ];
        
        $level = $levelMap[$errno] ?? 'ERROR';
        
        self::log($level, $errstr, [
            'file' => $errfile,
            'line' => $errline,
            'type' => $errno
        ]);
        
        return true;
    }
    
    /**
     * Handle uncaught exceptions
     */
    public static function handleException($exception)
    {
        global $_app_stage;
        
        self::log('CRITICAL', $exception->getMessage(), [
            'file' => $exception->getFile(),
            'line' => $exception->getLine(),
            'trace' => $exception->getTraceAsString(),
            'code' => $exception->getCode()
        ]);
        
        // Display user-friendly error message
        if (isset($_app_stage) && $_app_stage === 'Live') {
            if (!headers_sent()) {
                header('HTTP/1.1 500 Internal Server Error');
            }
            echo "<!DOCTYPE html><html><head><title>Error</title>";
            echo "<style>body{font-family:Arial,sans-serif;text-align:center;padding:50px;}";
            echo "h1{color:#dc2626;}p{color:#666;}</style></head><body>";
            echo "<h1>500 - Internal Server Error</h1>";
            echo "<p>We're sorry, but something went wrong. Please try again later.</p>";
            echo "<p><a href=\"" . APP_URL . "\" style=\"color:#2563eb;\">Go to Homepage</a></p>";
            echo "</body></html>";
        } else {
            // Development mode - show details
            echo "<h3>Exception: " . htmlspecialchars($exception->getMessage()) . "</h3>";
            echo "<p><strong>File:</strong> " . htmlspecialchars($exception->getFile()) . "</p>";
            echo "<p><strong>Line:</strong> " . $exception->getLine() . "</p>";
            echo "<pre>" . htmlspecialchars($exception->getTraceAsString()) . "</pre>";
        }
        
        exit(1);
    }
    
    /**
     * Handle fatal errors on shutdown
     */
    public static function handleShutdown()
    {
        $error = error_get_last();
        
        if ($error && in_array($error['type'], [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR])) {
            self::log('CRITICAL', $error['message'], [
                'file' => $error['file'],
                'line' => $error['line'],
                'type' => $error['type']
            ]);
        }
    }
    
    /**
     * Log access (for API endpoints)
     */
    public static function logAccess($method, $endpoint, $responseCode, $responseTime)
    {
        $timestamp = date('Y-m-d H:i:s');
        $ip = self::getClientIP();
        
        $logMessage = sprintf(
            "[%s] %s %s | IP: %s | Code: %d | Time: %.3fs\n",
            $timestamp,
            $method,
            $endpoint,
            $ip,
            $responseCode,
            $responseTime
        );
        
        $logFile = self::$logDir . self::$accessLog;
        self::writeLog($logFile, $logMessage);
    }
    
    /**
     * Get recent error logs
     * 
     * @param int $lines Number of lines to return
     * @return array
     */
    public static function getRecentErrors($lines = 50)
    {
        $logFile = self::$logDir . self::$errorLog;
        
        if (!file_exists($logFile)) {
            return [];
        }
        
        $content = file($logFile, FILE_IGNORE_NEW_LINES);
        return array_slice($content, -$lines);
    }
    
    /**
     * Clear log files
     */
    public static function clearLogs()
    {
        $errorLog = self::$logDir . self::$errorLog;
        $accessLog = self::$logDir . self::$accessLog;
        
        if (file_exists($errorLog)) {
            @unlink($errorLog);
        }
        
        if (file_exists($accessLog)) {
            @unlink($accessLog);
        }
    }
    
    /**
     * Write to log file with rotation
     */
    private static function writeLog($logFile, $message)
    {
        // Check file size and rotate if needed
        if (file_exists($logFile) && filesize($logFile) > self::$maxLogSize) {
            $rotatedFile = $logFile . '.' . date('Y-m-d-His');
            @rename($logFile, $rotatedFile);
            
            // Keep only last 5 rotated files
            self::cleanOldLogFiles(dirname($logFile));
        }
        
        // Write log
        @file_put_contents($logFile, $message, FILE_APPEND | LOCK_EX);
    }
    
    /**
     * Clean old log files
     */
    private static function cleanOldLogFiles($dir)
    {
        $files = glob($dir . '/*.log.*');
        
        if (count($files) > 5) {
            usort($files, function($a, $b) {
                return filemtime($a) - filemtime($b);
            });
            
            // Delete oldest files
            $toDelete = array_slice($files, 0, count($files) - 5);
            foreach ($toDelete as $file) {
                @unlink($file);
            }
        }
    }
    
    /**
     * Get client IP address
     */
    private static function getClientIP()
    {
        $ipKeys = [
            'HTTP_CLIENT_IP',
            'HTTP_X_FORWARDED_FOR',
            'HTTP_X_FORWARDED',
            'HTTP_X_CLUSTER_CLIENT_IP',
            'HTTP_FORWARDED_FOR',
            'HTTP_FORWARDED',
            'REMOTE_ADDR'
        ];
        
        foreach ($ipKeys as $key) {
            if (isset($_SERVER[$key]) && filter_var($_SERVER[$key], FILTER_VALIDATE_IP)) {
                return $_SERVER[$key];
            }
        }
        
        return $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0';
    }
    
    /**
     * Notify admin of critical errors (placeholder)
     */
    private static function notifyAdmin($message, $context)
    {
        // TODO: Implement email notification or push notification
        // For now, just log it
        $adminLog = self::$logDir . 'critical.log';
        $logMessage = sprintf(
            "[%s] CRITICAL ALERT: %s | Context: %s\n",
            date('Y-m-d H:i:s'),
            $message,
            json_encode($context)
        );
        @file_put_contents($adminLog, $logMessage, FILE_APPEND);
    }
}

// Initialize error handler
ErrorHandler::init();
