<?php
// Check if user is authenticated and is root
if (!defined('AUTH_USER')) {
    http_response_code(401);
    echo json_encode(array(
        'status' => 'error',
        'message' => 'Authentication required'
    ));
    exit();
}

if (AUTH_USER !== 'root') {
    http_response_code(403);
    echo json_encode(array(
        'status' => 'error',
        'message' => 'Root access required for update management'
    ));
    exit();
}

// Function to stream command output
function streamCommandOutput($command, $workingDir = null) {
    // Set headers for streaming
    header('Content-Type: text/plain');
    header('Cache-Control: no-cache');
    header('Connection: keep-alive');
    header('X-Accel-Buffering: no'); // Disable nginx buffering
    
    // Set unlimited execution time and increase memory limit
    set_time_limit(0);
    ini_set('memory_limit', '256M');
    
    // Disable all output buffering
    while (ob_get_level()) {
        ob_end_flush();
    }
    
    // Start implicit flush
    ob_implicit_flush(true);
    
    // Change to working directory if specified
    if ($workingDir && is_dir($workingDir)) {
        $originalDir = getcwd();
        chdir($workingDir);
    }
    
    // Start the process
    $descriptorspec = array(
        0 => array("pipe", "r"),  // stdin
        1 => array("pipe", "w"),  // stdout
        2 => array("pipe", "w")   // stderr
    );
    
    $process = proc_open($command, $descriptorspec, $pipes);
    
    if (is_resource($process)) {
        // Close stdin
        fclose($pipes[0]);
        
        // Set non-blocking mode for stdout and stderr
        stream_set_blocking($pipes[1], false);
        stream_set_blocking($pipes[2], false);
        
        // Read output in real-time
        $lastHeartbeat = time();
        $noOutputCount = 0;
        
        while (true) {
            $status = proc_get_status($process);
            $hasOutput = false;
            
            // Read from stdout
            $stdout = fread($pipes[1], 8192);
            if ($stdout !== false && $stdout !== '') {
                // Strip ANSI color codes and escape sequences
                $cleanOutput = preg_replace('/\x1b\[[0-9;]*m/', '', $stdout);
                // Fix escaped paths
                $cleanOutput = str_replace('\/', '/', $cleanOutput);
                // Remove extra backslashes
                $cleanOutput = str_replace('\\', '', $cleanOutput);
                
                echo json_encode(array('output' => $cleanOutput)) . "\n";
                flush();
                $hasOutput = true;
                $noOutputCount = 0;
            }
            
            // Read from stderr
            $stderr = fread($pipes[2], 8192);
            if ($stderr !== false && $stderr !== '') {
                // Strip ANSI color codes and escape sequences from error output too
                $cleanError = preg_replace('/\x1b\[[0-9;]*m/', '', $stderr);
                $cleanError = str_replace('\/', '/', $cleanError);
                $cleanError = str_replace('\\', '', $cleanError);
                
                echo json_encode(array('error' => $cleanError)) . "\n";
                flush();
                $hasOutput = true;
                $noOutputCount = 0;
            }
            
            // Send heartbeat if no output for a while
            if (!$hasOutput) {
                $noOutputCount++;
                if ($noOutputCount >= 50 && (time() - $lastHeartbeat) >= 5) { // Every 5 seconds
                    echo json_encode(array('heartbeat' => true)) . "\n";
                    flush();
                    $lastHeartbeat = time();
                    $noOutputCount = 0;
                }
            }
            
            // Check if process is still running
            if (!$status['running']) {
                break;
            }
            
            // Small delay to prevent excessive CPU usage
            usleep(100000); // 0.1 seconds
        }
        
        // Read any remaining output
        while (!feof($pipes[1])) {
            $stdout = fread($pipes[1], 8192);
            if ($stdout !== false && $stdout !== '') {
                // Clean remaining stdout
                $cleanOutput = preg_replace('/\x1b\[[0-9;]*m/', '', $stdout);
                $cleanOutput = str_replace('\/', '/', $cleanOutput);
                $cleanOutput = str_replace('\\', '', $cleanOutput);
                
                echo json_encode(array('output' => $cleanOutput)) . "\n";
                flush();
            }
        }
        
        while (!feof($pipes[2])) {
            $stderr = fread($pipes[2], 8192);
            if ($stderr !== false && $stderr !== '') {
                // Clean remaining stderr
                $cleanError = preg_replace('/\x1b\[[0-9;]*m/', '', $stderr);
                $cleanError = str_replace('\/', '/', $cleanError);
                $cleanError = str_replace('\\', '', $cleanError);
                
                echo json_encode(array('error' => $cleanError)) . "\n";
                flush();
            }
        }
        
        // Close pipes and process
        fclose($pipes[1]);
        fclose($pipes[2]);
        $exitCode = proc_close($process);
        
        // Output final status - handle special exit codes
        if ($exitCode == 141 || $exitCode == -1) {
            // Exit code 141 or -1 may indicate SIGPIPE, which can happen with successful updates
            echo json_encode(array(
                'output' => "Update process completed successfully"
            )) . "\n";
        } else if ($exitCode == 0) {
            echo json_encode(array(
                'output' => "Update completed successfully"
            )) . "\n";
        } else {
            echo json_encode(array(
                'output' => "Command completed with exit code: $exitCode",
                'exit_code' => $exitCode
            )) . "\n";
        }
        flush();
    } else {
        echo json_encode(array('error' => 'Failed to start process')) . "\n";
        flush();
    }
    
    // Restore original directory if changed
    if (isset($originalDir)) {
        chdir($originalDir);
    }
}

// Function to get simple command output
function getCommandOutput($command, $workingDir = null) {
    if ($workingDir && is_dir($workingDir)) {
        $originalDir = getcwd();
        chdir($workingDir);
    }
    
    $output = array();
    $exitCode = 0;
    exec($command . ' 2>&1', $output, $exitCode);
    
    if (isset($originalDir)) {
        chdir($originalDir);
    }
    
    return array(
        'output' => implode("\n", $output),
        'exit_code' => $exitCode
    );
}

// Handle different HTTP methods
switch ($_SERVER['REQUEST_METHOD']) {
    case 'POST':
        // Get JSON input
        $input = json_decode(file_get_contents('php://input'), true);
        
        if (!$input || !isset($input['action'])) {
            http_response_code(400);
            echo json_encode(array(
                'status' => 'error',
                'message' => 'Invalid JSON input or missing action'
            ));
            break;
        }
        
        switch ($input['action']) {
                
            case 'package_update':
                // Update system packages
                echo json_encode(array('output' => 'Starting package update...')) . "\n";
                flush();
                
                // Check if dnf or yum is available
                $packageManager = 'dnf';
                exec('which dnf', $output, $exitCode);
                if ($exitCode !== 0) {
                    $packageManager = 'yum';
                }
                
                echo json_encode(array('output' => "Using package manager: $packageManager")) . "\n";
                flush();
                
                // Update package cache
                streamCommandOutput("$packageManager makecache");
                
                // Update packages
                streamCommandOutput("$packageManager update -y");
                
                echo json_encode(array('output' => 'Package update process completed.')) . "\n";
                flush();
                break;
                
            case 'release_update':
                // Release-based update using download-update.sh
                $whpDir = '/root/whp';
                $downloadScript = "$whpDir/scripts/download-update.sh";
                
                if (!file_exists($downloadScript)) {
                    echo json_encode(array('error' => 'Release update script not found. Please migrate to the release system first.')) . "\n";
                    flush();
                    break;
                }
                
                echo json_encode(array('output' => 'Starting WHP release update...')) . "\n";
                flush();
                
                // Run the download-update script
                streamCommandOutput("$downloadScript --auto");
                
                echo json_encode(array('output' => 'Release update process completed.')) . "\n";
                flush();
                break;
                
                
                
            default:
                http_response_code(400);
                echo json_encode(array(
                    'status' => 'error',
                    'message' => 'Invalid action. Use package_update or release_update.'
                ));
                break;
        }
        break;
        
    case 'GET':
        // Handle GET requests for status checks
        $action = isset($_GET['action']) ? $_GET['action'] : '';
        
        switch ($action) {
                
            case 'package_check':
                // Check for available package updates
                $packageManager = 'dnf';
                exec('which dnf', $output, $exitCode);
                if ($exitCode !== 0) {
                    $packageManager = 'yum';
                }
                
                $result = getCommandOutput("$packageManager check-update 2>/dev/null | head -20");
                
                echo json_encode(array(
                    'status' => 'success',
                    'data' => $result['output'] ?: 'No updates available or unable to check.'
                ));
                break;
                
            default:
                http_response_code(400);
                echo json_encode(array(
                    'status' => 'error',
                    'message' => 'Invalid action. Use package_check.'
                ));
                break;
        }
        break;
        
    default:
        http_response_code(405);
        echo json_encode(array(
            'status' => 'error',
            'message' => 'Method not allowed. Use GET or POST.'
        ));
        break;
}
?> 