<?php
define('GATEWAY_VERSION', '1.0.0');

error_reporting(E_ALL);
ini_set('display_errors', 1);
ini_set('log_errors', 1);
// ini_set('error_log', dirname(__FILE__) . '/gateway-error.log');

// Cache control headers
header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');

// CORS headers
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: POST, GET');
header('Access-Control-Allow-Headers: Content-Type, Accept');

if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
    exit(0);
}

$input = json_decode(file_get_contents('php://input'), true);
$command = $input['command'] ?? '';
$path = $input['path'] ?? '';

function log_problem($path, $type, $details = '') {
    $message = date('[Y-m-d H:i:s]') . " Problem file - $type: $path";
    if ($details) {
        $message .= " ($details)";
    }
    // error_log($message);
}

function has_shell_access() {
    return function_exists('shell_exec') 
        && !in_array('shell_exec', array_map('trim', explode(',', ini_get('disable_functions')))) 
        && shell_exec('echo test') !== null
        && shell_exec('find --version') !== null;  // Verify find command works
}

function normalize_path($path) {
    // Replace multiple slashes with a single slash
    $path = preg_replace('#/+#', '/', $path);
    // Remove trailing slash
    return rtrim($path, '/');
}

function check_symlinks_shell($dir) {
    $cmd = "find " . escapeshellarg($dir) . " -type l -exec ls -l {} +";
    $output = shell_exec($cmd);
    
    if ($output === null) return false;
    
    $symlinks = [];
    $lines = array_filter(explode("\n", $output));
    
    foreach ($lines as $line) {
        if (preg_match('/.*\s(.*)\s->\s(.*)$/', $line, $matches)) {
            $path = trim($matches[1]);
            $target = trim($matches[2]);
            $symlinks[] = [
                'path' => $path,
                'target' => $target
            ];
        }
    }
    
    return $symlinks;
}

function check_symlinks_php($dir) {
    $symlinks = [];
    
    $iterator = new RecursiveIteratorIterator(
        new RecursiveDirectoryIterator($dir, RecursiveDirectoryIterator::SKIP_DOTS),
        RecursiveIteratorIterator::SELF_FIRST
    );
    
    foreach ($iterator as $path => $file) {
        if (is_link($path)) {
            $symlinks[] = [
                'path' => $path,
                'target' => readlink($path)
            ];
        }
    }
    
    return $symlinks;
}

function check_symlinks($dir) {
    if (!is_dir($dir)) return ['error' => 'Not a directory'];
    
    // Try shell method first if available
    if (has_shell_access()) {
        // error_log("Using shell command for symlink check");
        $result = check_symlinks_shell($dir);
        if ($result !== false) {
            return $result;
        }
        // error_log("Shell command failed, falling back to PHP implementation");
    }
    
    // PHP fallback
    // error_log("Using PHP implementation for symlink check");
    return check_symlinks_php($dir);
}

function scan_directory_shell($dir, &$debug, $symlinks) {
    // Get subdirectories only (exclude root)
    $cmd = "cd " . escapeshellarg($dir) . " && find . -mindepth 1 -type d -printf '%h/%f\n'";
    $dirs = shell_exec($cmd);
    
    if ($dirs === null) return false;
    
    $dirList = array_filter(explode("\n", $dirs));
    
    // Debug output
    $debug = [
        'scan_path' => $dir,
        'found_directories' => $dirList,
        'find_command' => $cmd,
        'find_output' => $dirs,
        'accessible_dirs_count' => 0,
        'root_counted' => false,
        'subdirs_found' => count($dirList),
        'processed_paths' => []
    ];
    
    $extensions = [];
    $filesByExtension = [];
    $totalFiles = 0;
    $forbiddenFiles = [];
    $accessibleDirs = 0; // Start at 0 and count all directories including root
    $forbiddenDirs = [];
    
    // Track root directory but don't count it
    $debug['processed_paths'][] = [
        'path' => $dir,
        'type' => 'directory',
        'readable' => is_readable($dir),
        'is_root' => true
    ];
    
    // Check each subdirectory for readability
    foreach ($dirList as $d) {
        // Remove leading ./
        $d = preg_replace('#^\./+#', '', $d);
        if (empty($d)) continue;
        
        $fullPath = normalize_path($dir . '/' . $d);
        if (!is_readable($fullPath)) {
            $forbiddenDirs[] = "Cannot access directory: " . $fullPath;
            $debug['processed_paths'][] = [
                'path' => $fullPath,
                'type' => 'directory',
                'readable' => false,
                'is_root' => false
            ];
        } else {
            $accessibleDirs++;
            $debug['accessible_dirs_count'] = $accessibleDirs;
            $debug['processed_paths'][] = [
                'path' => $fullPath,
                'type' => 'directory',
                'readable' => true,
                'is_root' => false
            ];
        }
    }
    
    // Now get all files
    $cmd = "cd " . escapeshellarg($dir) . " && find . -type f -printf '%h/%f\n'";
    $files = shell_exec($cmd);
    
    if ($files === null) return false;
    
    $fileList = array_filter(explode("\n", $files));
    
    foreach ($fileList as $file) {
        // Remove leading ./
        $file = preg_replace('#^\./+#', '', $file);
        if (empty($file)) continue;
        
        $fullPath = normalize_path($dir . '/' . $file);
        
        if (!is_readable($fullPath)) {
            $forbiddenFiles[] = "Cannot access file: " . $fullPath;
            continue;
        }
        
        $totalFiles++;
        $ext = strtolower(pathinfo($file, PATHINFO_EXTENSION)) ?: 'none';
        
        if (!isset($extensions[$ext])) {
            $extensions[$ext] = 0;
            $filesByExtension[$ext] = [];
        }
        $extensions[$ext]++;
        
        $fileInfo = [
            'name' => basename($file),
            'path' => $fullPath,
            'extension' => $ext
        ];
        
        $filesByExtension[$ext][] = $fileInfo;
    }
    
    // Sort extensions by count
    arsort($extensions);
    
    // Sort files within each extension by name
    foreach ($filesByExtension as &$files) {
        usort($files, function($a, $b) {
            return strcmp($a['name'], $b['name']);
        });
    }
    
    return [
        'files' => $totalFiles + count($forbiddenFiles),
        'forbidden_files' => count($forbiddenFiles),
        'accessible_directories' => $accessibleDirs,
        'forbidden_directories' => count($forbiddenDirs),
        'forbidden_list' => array_merge($forbiddenDirs, $forbiddenFiles),
        'extensions' => $extensions,
        'filesByExtension' => $filesByExtension,
        'symlinks' => $symlinks,                    // Add symlinks data
        'symlink_count' => count($symlinks)         // Add symlink count
    ];
}

function scan_directory_php_recursive($dir, &$files, &$forbiddenFiles, &$accessibleDirs, &$forbiddenDirs, &$extensions, &$filesByExtension, $isRoot = true) {
    // Normalize directory path
    $dir = normalize_path($dir);
    
    // Check current directory
    if (!is_readable($dir)) {
        $forbiddenDirs[] = "Cannot access directory: " . $dir;
        return;
    }

    // Get all items in directory
    $items = scandir($dir);
    foreach ($items as $item) {
        if ($item === '.' || $item === '..') continue;
        
        $fullPath = normalize_path($dir . '/' . $item);
        
        if (is_dir($fullPath)) {
            if (!is_readable($fullPath)) {
                $forbiddenDirs[] = "Cannot access directory: " . $fullPath;
            } else {
                // Only count non-root directories
                if (!$isRoot) {
                    $accessibleDirs++;
                }
                scan_directory_php_recursive($fullPath, $files, $forbiddenFiles, $accessibleDirs, $forbiddenDirs, $extensions, $filesByExtension, false);
            }
        } else if (is_file($fullPath)) {
            if (!is_readable($fullPath)) {
                $forbiddenFiles[] = "Cannot access file: " . $fullPath;
            } else {
                $files++;
                // Get file extension
                $ext = strtolower(pathinfo($item, PATHINFO_EXTENSION));
                $ext = $ext === '' ? 'none' : $ext;
                
                // Count extension
                if (!isset($extensions[$ext])) {
                    $extensions[$ext] = 0;
                    $filesByExtension[$ext] = [];
                }
                $extensions[$ext]++;
                
                // Store file info
                $fileInfo = [
                    'name' => $item,
                    'path' => $fullPath,
                    'extension' => $ext
                ];

                $filesByExtension[$ext][] = $fileInfo;
            }
        }
    }
}

function scan_directory_php($dir) {
    if (!is_dir($dir)) return ['error' => 'Not a directory'];

    $files = 0;
    $forbiddenFiles = [];
    $accessibleDirs = 0;
    $forbiddenDirs = [];
    $extensions = [];
    $filesByExtension = [];

    scan_directory_php_recursive($dir, $files, $forbiddenFiles, $accessibleDirs, $forbiddenDirs, $extensions, $filesByExtension, true);

    // Sort extensions by count
    arsort($extensions);

    // Sort files within each extension by name
    foreach ($filesByExtension as &$files) {
        usort($files, function($a, $b) {
            return strcmp($a['name'], $b['name']);
        });
    }

    // Get symlinks using PHP method
    $symlinks = check_symlinks_php($dir);

    return [
        'files' => (int)$files + count($forbiddenFiles),
        'forbidden_files' => count($forbiddenFiles),
        'accessible_directories' => $accessibleDirs,
        'forbidden_directories' => count($forbiddenDirs),
        'forbidden_list' => array_merge($forbiddenDirs, $forbiddenFiles),
        'extensions' => $extensions,
        'filesByExtension' => $filesByExtension,
        'symlinks' => $symlinks,                    // Add symlinks data
        'symlink_count' => count($symlinks)         // Add symlink count
    ];
}

function scan_directory($dir) {
    if (!is_dir($dir)) return ['error' => 'Not a directory'];

    // First check for symlinks
    $symlinks = check_symlinks($dir);
    if (isset($symlinks['error'])) {
        return $symlinks;
    }

    // Check shell availability
    $shell_available = has_shell_access();
    // error_log("Shell exec availability: " . ($shell_available ? "Available" : "Not available"));
    
    $debug = [];
    
    // Try shell command first if available
    if ($shell_available) {
        // error_log("Using shell commands (Linux) for directory scan");
        $result = scan_directory_shell($dir, $debug, $symlinks);  // Pass symlinks here
        if ($result !== false) {
            // If we get here, shell scanning worked successfully
            $result['scan_method'] = 'shell';
            $result['debug'] = $debug;
            return $result;  // No need to add symlinks here anymore
        }
        // error_log("Shell command failed, falling back to PHP implementation");
    }
    
    // Fall back to PHP implementation
    // error_log("Using PHP implementation for directory scan");
    $result = scan_directory_php($dir);
    $result['scan_method'] = 'php';
    return $result;
}

function chmod_file_shell($path, $mode) {
    $cmd = sprintf("chmod %o %s", $mode, escapeshellarg($path));
    $output = shell_exec($cmd);
    
    if ($output === null) {
        // error_log("Shell chmod command failed");
        return false;
    }
    // error_log("Successfully changed permissions using shell command");
    return ['success' => true];
}

function chmod_file($path) {
    // Normalize file path
    $path = normalize_path($path);
    
    if (!file_exists($path)) {
        return ['error' => 'File not found'];
    }
    
    try {
        // Set mode based on type
        $mode = is_dir($path) ? 0755 : 0644;
        
        // Try shell method first if available
        if (has_shell_access()) {
            // error_log("Attempting to chmod using shell command");
            $result = chmod_file_shell($path, $mode);
            if ($result !== false) {
                return $result;
            }
            // error_log("Shell command failed, falling back to PHP implementation");
        }
        
        // PHP fallback
        if (chmod($path, $mode)) {
            // error_log("Successfully changed permissions using PHP implementation");
            return ['success' => true];
        } else {
            // error_log("Failed to chmod using PHP implementation");
            return ['error' => 'Failed to chmod'];
        }
    } catch (Exception $e) {
        // error_log("Exception during chmod: " . $e->getMessage());
        return ['error' => 'Exception during chmod: ' . $e->getMessage()];
    }
}

function delete_file_shell($path) {
    $cmd = "rm " . escapeshellarg($path);
    $output = shell_exec($cmd);
    
    if ($output === null) {
        // error_log("Shell delete command failed");
        return false;
    }
    // error_log("Successfully deleted file using shell command");
    return ['success' => true];
}

function delete_file($path) {
    // Normalize file path
    $path = normalize_path($path);
    
    if (!file_exists($path)) {
        return ['error' => 'File not found'];
    }
    
    if (!is_writable($path)) {
        return ['error' => 'File not writable'];
    }
    
    try {
        // Try shell method first if available
        if (has_shell_access()) {
            // error_log("Attempting to delete file using shell command");
            $result = delete_file_shell($path);
            if ($result !== false) {
                return $result;
            }
            // error_log("Shell command failed, falling back to PHP implementation");
        }
        
        // PHP fallback
        if (unlink($path)) {
            // error_log("Successfully deleted file using PHP implementation");
            return ['success' => true];
        } else {
            // error_log("Failed to delete file using PHP implementation");
            return ['error' => 'Failed to delete file'];
        }
    } catch (Exception $e) {
        // error_log("Exception deleting file: " . $e->getMessage());
        return ['error' => 'Exception deleting file: ' . $e->getMessage()];
    }
}

function view_file_shell($path) {
    // Use 'cat' command for faster reading of large files
    $cmd = "cat " . escapeshellarg($path);
    $content = shell_exec($cmd);
    
    if ($content !== null) {
        // error_log("Successfully read file using shell command");
        return ['content' => $content];
    }
    return false;
}

function view_file($path) {
    // Normalize file path
    $path = normalize_path($path);
    
    // error_log("Attempting to read file: " . $path);
    
    if (!file_exists($path)) {
        // error_log("File not found: " . $path);
        return ['error' => 'File not found'];
    }
    
    if (!is_readable($path)) {
        // error_log("File not readable: " . $path);
        return ['error' => 'File not readable'];
    }
    
    try {
        // Try shell method first if available
        if (has_shell_access()) {
            // error_log("Attempting to read file using shell command");
            $result = view_file_shell($path);
            if ($result !== false) {
                return $result;
            }
            // error_log("Shell command failed, falling back to PHP implementation");
        }
        
        // PHP fallback
        $content = file_get_contents($path);
        if ($content === false) {
            // error_log("Failed to read file: " . $path);
            return ['error' => 'Failed to read file: ' . error_get_last()['message']];
        }
        
        // error_log("Successfully read file. Content length: " . strlen($content));
        return ['content' => $content];
    } catch (Exception $e) {
        // error_log("Exception reading file: " . $e->getMessage());
        return ['error' => 'Exception reading file: ' . $e->getMessage()];
    }
}

function batch_view_files_shell($paths) {
    $results = [];
    
    // Set higher memory limit and execution time for large batches
    ini_set('memory_limit', '1024M');
    set_time_limit(600); // 10 minutes
    
    // Disable output buffering
    while (ob_get_level()) ob_end_clean();
    
    foreach ($paths as $path) {
        try {
            // error_log("Processing file: " . $path);
            
            $normalizedPath = normalize_path($path);
            if (!file_exists($normalizedPath)) {
                log_problem($path, 'Does not exist');
                continue;
            }
            
            if (!is_readable($normalizedPath)) {
                log_problem($path, 'Not readable');
                continue;
            }
            
            $fileSize = filesize($normalizedPath);
            if ($fileSize > 5 * 1024 * 1024) {
                log_problem($path, 'Too large', ($fileSize/1024/1024) . 'MB');
                continue;
            }
            
            // Read file in chunks
            $content = '';
            $handle = fopen($normalizedPath, 'r');
            if ($handle) {
                while (!feof($handle)) {
                    $chunk = fread($handle, 8192);
                    if ($chunk === false) break;
                    $content .= $chunk;
                }
                fclose($handle);
                
                // Log successful read
                $contentSize = strlen($content);
                // error_log("Read successful: " . $path . " (size: " . $contentSize . " bytes)");
            }
            
            if ($content !== null) {
                // Try common encodings
                $encodings = ['UTF-8', 'SJIS', 'EUC-JP', 'ASCII'];
                foreach ($encodings as $encoding) {
                    if (mb_check_encoding($content, $encoding)) {
                        if ($encoding !== 'UTF-8') {
                            // error_log("Converting file from $encoding to UTF-8: " . $path);
                            $content = mb_convert_encoding($content, 'UTF-8', $encoding);
                        }
                        break;
                    }
                }
                // If no encoding detected, force convert from SJIS
                if (!mb_check_encoding($content, 'UTF-8')) {
                    // error_log("Forcing file conversion from SJIS to UTF-8: " . $path);
                    $content = mb_convert_encoding($content, 'UTF-8', 'SJIS');
                }
                
                // error_log("Adding to results: " . $path);
                $results[$path] = [
                    'success' => true,
                    'content' => $content
                ];
                
                unset($content);
                gc_collect_cycles();
            }
            
        } catch (Exception $e) {
            // error_log("Failed to process " . $path . ": " . $e->getMessage());
            $results[$path] = [
                'success' => false,
                'error' => $e->getMessage()
            ];
        }
    }
    
    return $results;
}

function batch_view_files($paths) {
    // Set higher memory limit and execution time for large batches
    ini_set('memory_limit', '512M');
    set_time_limit(300); // 5 minutes
    
    // Try shell method first if available
    if (has_shell_access()) {
        // error_log("Attempting batch view using shell commands");
        $results = batch_view_files_shell($paths);
        if ($results !== false) {
            return $results;
        }
        // error_log("Shell commands failed, falling back to PHP implementation");
    }
    
    // PHP fallback
    $results = [];
    foreach ($paths as $path) {
        try {
            $result = view_file($path);
            $results[$path] = [
                'success' => !isset($result['error']),
                'content' => $result['content'] ?? null,
                'error' => $result['error'] ?? null
            ];
            unset($result);               // Clear result
            gc_collect_cycles();          // Force garbage collection
        } catch (Exception $e) {
            // error_log("Exception reading file {$path}: " . $e->getMessage());
            $results[$path] = [
                'success' => false,
                'error' => $e->getMessage()
            ];
        }
    }

    return $results;
}

function download_file_shell($path) {
    try {
        // Get file info
        $filename = basename($path);
        $filesize = filesize($path);
        $mime_type = mime_content_type($path);
        
        // Set headers for download
        header('Content-Type: ' . $mime_type);
        header('Content-Length: ' . $filesize);
        header('Content-Disposition: attachment; filename="' . $filename . '"');
        header('Cache-Control: no-cache');
        
        // Use passthru to directly output the file content
        $cmd = "cat " . escapeshellarg($path);
        $result = passthru($cmd);
        
        if ($result === false) {
            // error_log("Shell download command failed");
            return false;
        }
        
        // error_log("Successfully downloaded file using shell command");
        return true;
    } catch (Exception $e) {
        // error_log("Exception in shell download: " . $e->getMessage());
        return false;
    }
}

function download_file($path) {
    // Normalize file path
    $path = normalize_path($path);
    
    if (!file_exists($path)) {
        header('Content-Type: application/json');
        echo json_encode(['error' => 'File not found']);
        return;
    }
    
    if (!is_readable($path)) {
        header('Content-Type: application/json');
        echo json_encode(['error' => 'File not readable']);
        return;
    }
    
    try {
        // Try shell method first if available
        if (has_shell_access()) {
            // error_log("Attempting to download file using shell command");
            $result = download_file_shell($path);
            if ($result !== false) {
                return;
            }
            // error_log("Shell command failed, falling back to PHP implementation");
        }
        
        // PHP fallback
        $content = file_get_contents($path);
        if ($content === false) {
            header('Content-Type: application/json');
            echo json_encode(['error' => 'Failed to read file']);
            return;
        }
        
        // Get file info
        $filename = basename($path);
        $filesize = strlen($content);
        $mime_type = mime_content_type($path);
        
        // Set headers for download
        header('Content-Type: ' . $mime_type);
        header('Content-Length: ' . $filesize);
        header('Content-Disposition: attachment; filename="' . $filename . '"');
        header('Cache-Control: no-cache');
        
        // Output file content
        echo $content;
        // error_log("Successfully downloaded file using PHP implementation");
    } catch (Exception $e) {
        // error_log("Exception downloading file: " . $e->getMessage());
        header('Content-Type: application/json');
        echo json_encode(['error' => 'Exception reading file: ' . $e->getMessage()]);
    }
}

try {
    switch ($command) {
        case 'test':
            header('Content-Type: application/json');
            echo json_encode([
                'success' => true,
                'data' => [
                    'gateway_path' => normalize_path(dirname(__FILE__)),
                    'gateway_file' => basename(__FILE__),
                    'version' => GATEWAY_VERSION
                ]
            ]);
            break;

        case 'scan':
            if (empty($path)) {
                header('Content-Type: application/json');
                echo json_encode([
                    'success' => false,
                    'error' => 'Path is required'
                ]);
                break;
            }

            $scan = scan_directory($path);
            
            if (isset($scan['error'])) {
                header('Content-Type: application/json');
                echo json_encode([
                    'success' => false,
                    'error' => $scan['error']
                ]);
                break;
            }

            // Get disk space info
            $totalSpace = disk_total_space($path);
            $freeSpace = disk_free_space($path);
            $totalGB = round($totalSpace / (1024 * 1024 * 1024), 2);
            $freeGB = round($freeSpace / (1024 * 1024 * 1024), 2);
            $usedPercent = round(($totalSpace - $freeSpace) / $totalSpace * 100);

            // Get PHP memory limit
            $memoryLimit = ini_get('memory_limit');
            
            // Get max execution time
            $executionTime = ini_get('max_execution_time');
            
            // Check temp dir access
            $tempDirAccess = is_writable(sys_get_temp_dir());
            
            // Get disabled functions
            $disabledFunctions = array_map('trim', explode(',', ini_get('disable_functions')));
            
            // Check HTTP client capabilities
            $curlAvailable = function_exists('curl_init');
            $fgetAvailable = function_exists('file_get_contents') && function_exists('stream_context_create');
            $fsockopenAvailable = function_exists('fsockopen');
            
            // Check SSL support
            $sslSupport = defined('CURL_VERSION_SSL') && function_exists('curl_version') && (curl_version()['features'] & CURL_VERSION_SSL);
            
            header('Content-Type: application/json');
            echo json_encode([
                'success' => true,
                'data' => [
                    'files' => $scan['files'],
                    'directories' => $scan['accessible_directories'] + $scan['forbidden_directories'],
                    'accessible_directories' => $scan['accessible_directories'],
                    'forbidden_directories' => $scan['forbidden_directories'],
                    'forbidden_files' => $scan['forbidden_files'],
                    'forbidden_list' => $scan['forbidden_list'],
                    'extensions' => $scan['extensions'],
                    'filesByExtension' => $scan['filesByExtension'],
                    'symlinks' => $scan['symlinks'],
                    'symlink_count' => $scan['symlink_count'],
                    'path' => normalize_path($path),
                    'serverInfo' => [
                        'shell' => [
                            'available' => has_shell_access(),
                            'disabledFunctions' => $disabledFunctions,
                            'commandExecution' => has_shell_access(),
                            'os' => PHP_OS_FAMILY ?? PHP_OS
                        ],
                        'fileSystem' => [
                            'scanMethod' => $scan['scan_method'] ?? 'php',
                            'permissions' => [
                                'read' => is_readable($path),
                                'write' => is_writable($path),
                                'execute' => is_executable($path)
                            ]
                        ],
                        'httpClient' => [
                            'curl' => $curlAvailable,
                            'fileGetContents' => $fgetAvailable,
                            'fsockopen' => $fsockopenAvailable,
                            'ssl' => $sslSupport
                        ],
                        'resources' => [
                            'memoryLimit' => $memoryLimit,
                            'executionTime' => (int)$executionTime,
                            'tempDirAccess' => $tempDirAccess,
                            'disk' => [
                                'total' => $totalGB,
                                'free' => $freeGB,
                                'usedPercent' => $usedPercent
                            ]
                        ]
                    ]
                ]
            ]);
            break;

        case 'view':
            if (empty($path)) {
                header('Content-Type: application/json');
                echo json_encode([
                    'success' => false,
                    'error' => 'Path is required'
                ]);
                break;
            }

            $result = view_file($path);
            
            if (isset($result['error'])) {
                header('Content-Type: application/json');
                echo json_encode([
                    'success' => false,
                    'error' => $result['error']
                ]);
                break;
            }

            header('Content-Type: application/json');
            echo json_encode([
                'success' => true,
                'data' => [
                    'content' => $result['content']
                ]
            ]);
            break;

        case 'edit':
            if (empty($path)) {
                header('Content-Type: application/json');
                echo json_encode([
                    'success' => false,
                    'error' => 'Path is required'
                ]);
                break;
            }

            if (!isset($input['content'])) {
                header('Content-Type: application/json');
                echo json_encode([
                    'success' => false,
                    'error' => 'Content is required'
                ]);
                break;
            }

            // Normalize file path
            $path = normalize_path($path);
            
            if (!file_exists($path)) {
                header('Content-Type: application/json');
                echo json_encode([
                    'success' => false,
                    'error' => 'File not found'
                ]);
                break;
            }
            
            if (!is_writable($path)) {
                header('Content-Type: application/json');
                echo json_encode([
                    'success' => false,
                    'error' => 'File not writable'
                ]);
                break;
            }
            
            try {
                // Try shell method first if available
                if (has_shell_access()) {
                    // error_log("Attempting to write file using shell command");
                    // Create a temporary file with the content
                    $tempFile = tempnam(sys_get_temp_dir(), 'edit_');
                    if ($tempFile === false) {
                        throw new Exception('Failed to create temporary file');
                    }
                    
                    if (file_put_contents($tempFile, $input['content']) === false) {
                        unlink($tempFile);
                        throw new Exception('Failed to write to temporary file');
                    }
                    
                    // Use cat to write the content (handles large files better)
                    $cmd = sprintf("cat %s > %s", escapeshellarg($tempFile), escapeshellarg($path));
                    $output = shell_exec($cmd);
                    unlink($tempFile); // Clean up temp file
                    
                    if ($output === null) {
                        // error_log("Shell write command failed, falling back to PHP implementation");
                    } else {
                        // error_log("Successfully wrote file using shell command");
                        header('Content-Type: application/json');
                        echo json_encode(['success' => true]);
                        break;
                    }
                }
                
                // PHP fallback
                if (file_put_contents($path, $input['content']) !== false) {
                    // error_log("Successfully wrote file using PHP implementation");
                    header('Content-Type: application/json');
                    echo json_encode(['success' => true]);
                } else {
                    // error_log("Failed to write file using PHP implementation");
                    header('Content-Type: application/json');
                    echo json_encode([
                        'success' => false,
                        'error' => 'Failed to write file'
                    ]);
                }
            } catch (Exception $e) {
                // error_log("Exception writing file: " . $e->getMessage());
                header('Content-Type: application/json');
                echo json_encode([
                    'success' => false,
                    'error' => 'Exception writing file: ' . $e->getMessage()
                ]);
            }
            break;

        case 'delete':
            if (empty($path)) {
                header('Content-Type: application/json');
                echo json_encode([
                    'success' => false,
                    'error' => 'Path is required'
                ]);
                break;
            }

            header('Content-Type: application/json');
            $result = delete_file($path);
            
            if (isset($result['error'])) {
                echo json_encode([
                    'success' => false,
                    'error' => $result['error']
                ]);
            } else {
                echo json_encode([
                    'success' => true,
                    'path' => $path
                ]);
            }
            break;

        case 'chmod':
            if (empty($path)) {
                header('Content-Type: application/json');
                echo json_encode([
                    'success' => false,
                    'error' => 'Path is required'
                ]);
                break;
            }

            $result = chmod_file($path);
            
            if (isset($result['error'])) {
                header('Content-Type: application/json');
                echo json_encode([
                    'success' => false,
                    'error' => $result['error']
                ]);
                break;
            }

            header('Content-Type: application/json');
            echo json_encode([
                'success' => true
            ]);
            break;

        case 'batch_view':
            header('Content-Type: application/json');
            
            if (empty($input['paths']) || !is_array($input['paths'])) {
                echo json_encode([
                    'success' => false,
                    'error' => 'Paths array is required'
                ]);
                break;
            }
        
            $results = batch_view_files($input['paths']);
            
            // Ensure all content is UTF-8
            array_walk_recursive($results, function(&$item) {
                if (is_string($item)) {
                    // Try common encodings
                    $encodings = ['UTF-8', 'SJIS', 'EUC-JP', 'ASCII'];
                    foreach ($encodings as $encoding) {
                        if (mb_check_encoding($item, $encoding)) {
                            if ($encoding !== 'UTF-8') {
                                // error_log("Converting from $encoding to UTF-8");
                                $item = mb_convert_encoding($item, 'UTF-8', $encoding);
                            }
                            break;
                        }
                    }
                    // If no encoding detected, force convert from SJIS
                    if (!mb_check_encoding($item, 'UTF-8')) {
                        // error_log("Forcing conversion from SJIS to UTF-8");
                        $item = mb_convert_encoding($item, 'UTF-8', 'SJIS');
                    }
                }
            });
            
            // Encode response
            $json = json_encode([
                'success' => true,
                'data' => $results
            ]);
            
            if ($json === false) {
                // error_log("JSON encode error: " . json_last_error_msg());
                echo json_encode([
                    'success' => false,
                    'error' => 'Failed to encode response'
                ]);
                break;
            }
            
            // Log response size
            $size = strlen($json);
            // error_log("Sending response (size: {$size} bytes)");
            
            // Send response
            echo $json;
            break;

        case 'update':
            if (!isset($input['content'])) {
                header('Content-Type: application/json');
                echo json_encode([
                    'success' => false,
                    'error' => 'Gateway content is required'
                ]);
                break;
            }

            try {
                // Write new content to gateway file
                if (file_put_contents(__FILE__, $input['content']) === false) {
                    throw new Exception('Failed to write gateway file');
                }

                // Clear opcache if available
                if (function_exists('opcache_reset')) {
                    opcache_reset();
                }
                if (function_exists('apc_clear_cache')) {
                    apc_clear_cache();
                }

                // Clear realpath cache
                clearstatcache(true, __FILE__);

                header('Content-Type: application/json');
                echo json_encode(['success' => true]);
            } catch (Exception $e) {
                header('Content-Type: application/json');
                echo json_encode([
                    'success' => false,
                    'error' => 'Failed to update gateway: ' . $e->getMessage()
                ]);
            }
            break;

        case 'download':
            if (empty($path)) {
                header('Content-Type: application/json');
                echo json_encode([
                    'success' => false,
                    'error' => 'Path is required'
                ]);
                break;
            }

            download_file($path);
            break;

        default:
            header('Content-Type: application/json');
            echo json_encode([
                'success' => false,
                'error' => 'Invalid command'
            ]);
        }
} catch (Exception $e) {
    // error_log("Fatal error: " . $e->getMessage());
    header('Content-Type: application/json');
    echo json_encode([
        'success' => false,
        'error' => 'Server error: ' . $e->getMessage()
    ]);
}
