<?php

namespace ServerManager\UI;

use PHPNative\Ui\Widget\Button;
use PHPNative\Ui\Widget\Container;
use PHPNative\Ui\Widget\FileBrowser;
use PHPNative\Ui\Widget\Icon;
use PHPNative\Ui\Widget\Label;
use PHPNative\Ui\Widget\Modal;
use PHPNative\Ui\Widget\TextArea;
use PHPNative\Ui\Widget\TextInput;
use PHPNative\Ui\Widget\ProgressBar;

class SftpManagerTab
{
    private Container $tab;
    private FileBrowser $localFileBrowser;
    private FileBrowser $remoteFileBrowser;
    private Label $connectionStatusLabel;
    private Modal $editModal;
    private TextArea $fileEditor;
    private Label $filePathLabel;
    private string $currentEditFilePath = '';
    private Modal $filenameModal;
    private TextInput $filenameInput;
    private Modal $renameModal;
    private TextInput $renameInput;
    private Label $renamePathLabel;
    private string $currentRenameFilePath = '';
    private string $currentRenameMode = 'remote';
    private Modal $deleteConfirmModal;
    private string $currentDeleteFilePath = '';
    private Label $deleteConfirmLabel;
    private null|array $currentLocalSelection = null;
    private null|array $currentRemoteSelection = null;
    private ?string $lastRemoteClickPath = null;
    private float $lastRemoteClickTime = 0.0;
    private ProgressBar $transferProgressBar;
    private Label $transferInfoLabel;
    private Label $transferBytesLabel;
    private array $pendingUploadQueue = [];
    private int $totalUploadFiles = 0;
    private int $completedUploadFiles = 0;
    private int $totalUploadBytes = 0;
    private int $completedUploadBytes = 0;
    private array $pendingDownloadQueue = [];
    private int $totalDownloadFiles = 0;
    private int $completedDownloadFiles = 0;
    private int $totalDownloadBytes = 0;
    private int $completedDownloadBytes = 0;

    public function __construct(
        string &$apiKey,
        string &$privateKeyPath,
        string &$remoteStartDir,
        ServerListTab $serverListTab,
        \PHPNative\Ui\Widget\TabContainer $tabContainer,
        Label $statusLabel,
    ) {
        $this->tab = new Container('flex flex-row p-4 gap-4 bg-gray-50');
        $currentPrivateKeyPath = &$privateKeyPath;
        $currentRemoteStartDir = &$remoteStartDir;

        // Left side: Local file browser
        // Lokaler Browser: Spalte, Scrollen übernimmt der FileBrowser selbst
        $localBrowserContainer = new Container('flex flex-col flex-1 gap-2');
        $localBrowserContainer->addComponent(new Label('Lokal', 'text-lg font-bold text-black mb-2'));
        $this->localFileBrowser = new FileBrowser(
            getcwd(),
            false,
            'flex-1 bg-white border-2 border-gray-300 rounded p-2',
        );
        $localBrowserContainer->addComponent($this->localFileBrowser);

        // Track local file selection for uploads
        $sftpTab = $this;
        $this->localFileBrowser->setOnFileSelect(function ($path, $row) use ($sftpTab) {
            $sftpTab->currentLocalSelection = [
                'path' => $path,
                'row' => $row,
            ];
        });

        // Right side: Remote file browser
        // Remote-Browser: Spalte, Scrollen übernimmt der FileBrowser selbst
        $remoteBrowserContainer = new Container('flex flex-col flex-1 gap-2');

        // Header with title and new file button
        $remoteHeader = new Container('flex flex-row items-center gap-2 mb-2');
        $remoteHeader->addComponent(new Label('Remote', 'text-lg font-bold text-black flex-1'));

        $newFileButton = new Button('', 'px-3 py-2 bg-green-600 text-white rounded hover:bg-green-700 flex items-center justify-center');
        $newFileIcon = new Icon(\PHPNative\Tailwind\Data\Icon::plus, 16, 'text-white');
        $newFileButton->setIcon($newFileIcon);
        $remoteHeader->addComponent($newFileButton);
        $remoteBrowserContainer->addComponent($remoteHeader);

        $this->remoteFileBrowser = new FileBrowser('/', true, 'flex-1 bg-white border-2 border-gray-300 rounded p-2');
        $remoteBrowserContainer->addComponent($this->remoteFileBrowser);

        // Connection status label
        $this->connectionStatusLabel = new Label('Nicht verbunden', 'text-sm text-gray-600 italic mb-2');
        $remoteBrowserContainer->addComponent($this->connectionStatusLabel);

        // Middle: Transfer buttons (Upload/Download)
        $transferContainer = new Container('flex flex-col justify-center items-center gap-2 w-[180]');

        $uploadButton = new Button(
            'Hochladen →',
            'w-full px-3 py-2 bg-green-600 text-white rounded hover:bg-green-700',
        );
        $downloadButton = new Button(
            '← Herunterladen',
            'w-full px-3 py-2 bg-blue-600 text-white rounded hover:bg-blue-700',
        );
        $transferContainer->addComponent($uploadButton);
        $transferContainer->addComponent($downloadButton);

        // Transfer-Info + ProgressBar
        $this->transferInfoLabel = new Label('Kein Transfer aktiv', 'text-xs text-gray-600 mt-2');
        $this->transferBytesLabel = new Label('', 'text-xs text-gray-600');
        $this->transferProgressBar = new ProgressBar('mt-1');
        $this->transferProgressBar->setValue(0.0);
        $transferContainer->addComponent($this->transferInfoLabel);
        $transferContainer->addComponent($this->transferBytesLabel);
        $transferContainer->addComponent($this->transferProgressBar);

        $this->tab->addComponent($localBrowserContainer);
        $this->tab->addComponent($transferContainer);
        $this->tab->addComponent($remoteBrowserContainer);

        // Setup remote navigation handler
        $this->setupRemoteNavigationHandler($currentPrivateKeyPath, $serverListTab, $statusLabel);

        // Setup SFTP connection handler
        $this->setupSftpConnectionHandler($currentPrivateKeyPath, $currentRemoteStartDir, $serverListTab, $tabContainer, $statusLabel);

        // Create edit modal
        $this->createEditModal($currentPrivateKeyPath, $serverListTab, $statusLabel);

        // Create filename input modal
        $this->createFilenameModal($currentPrivateKeyPath, $serverListTab, $statusLabel);

        // Create rename modal
        $this->createRenameModal($currentPrivateKeyPath, $serverListTab, $statusLabel);

        // Create delete confirmation modal
        $this->createDeleteConfirmModal($currentPrivateKeyPath, $serverListTab, $statusLabel);

        // Setup local rename handler
        $this->localFileBrowser->setOnRenameFile(function ($path, $row) use ($sftpTab, $statusLabel) {
            $sftpTab->handleLocalRename($path, $row, $statusLabel);
        });

        // Setup transfer button handlers
        $uploadButton->setOnClick(function () use ($sftpTab, &$currentPrivateKeyPath, $serverListTab, $statusLabel) {
            $sftpTab->handleUpload($currentPrivateKeyPath, $serverListTab, $statusLabel);
        });

        $downloadButton->setOnClick(function () use ($sftpTab, &$currentPrivateKeyPath, $serverListTab, $statusLabel) {
            $sftpTab->handleDownload($currentPrivateKeyPath, $serverListTab, $statusLabel);
        });

        // Setup file edit handler
        $this->remoteFileBrowser->setOnEditFile(function ($path, $row) use (
            &$currentPrivateKeyPath,
            $serverListTab,
            $statusLabel,
        ) {
            $this->handleFileEdit($path, $row, $currentPrivateKeyPath, $serverListTab, $statusLabel);
        });

        // Setup new file button handler
        $sftpTab = $this;
        $newFileButton->setOnClick(function () use ($sftpTab, &$currentPrivateKeyPath, $serverListTab, $statusLabel) {
            $sftpTab->handleNewFile($currentPrivateKeyPath, $serverListTab, $statusLabel);
        });

        // Setup rename handler
        $this->remoteFileBrowser->setOnRenameFile(function ($path, $row) use (
            $sftpTab,
            &$currentPrivateKeyPath,
            $serverListTab,
            $statusLabel,
        ) {
            $sftpTab->handleFileRename($path, $row, $currentPrivateKeyPath, $serverListTab, $statusLabel);
        });

        // Setup delete handler
        $this->remoteFileBrowser->setOnDeleteFile(function ($path, $row) use (
            $sftpTab,
            &$currentPrivateKeyPath,
            $serverListTab,
            $statusLabel,
        ) {
            $sftpTab->handleFileDelete($path, $row, $currentPrivateKeyPath, $serverListTab, $statusLabel);
        });
    }

    private function setupRemoteNavigationHandler(
        string &$currentPrivateKeyPath,
        ServerListTab $serverListTab,
        Label $statusLabel,
    ): void {
        $sftpTab = $this;
        // Create reference to selectedServer array outside of closure
        $selectedServerRef = &$serverListTab->selectedServer;

        $this->remoteFileBrowser->setOnFileSelect(
            function ($path, $row) use (
                $sftpTab,
                &$currentPrivateKeyPath,
                &$selectedServerRef,
                $statusLabel,
            ) {
                // Track remote selection (for downloads)
                $sftpTab->currentRemoteSelection = [
                    'path' => $path,
                    'row' => $row,
                ];

                // Only navigate when a directory is selected
                if (!isset($row['isDir']) || !$row['isDir']) {
                    return;
                }

                // Require double click for navigation:
                // first click selektiert nur, zweiter Klick (innerhalb kurzer Zeit)
                // öffnet das Verzeichnis.
                $now = microtime(true);
                $doubleClickThreshold = 0.4; // Sekunden

                if (
                    $sftpTab->lastRemoteClickPath !== $path ||
                    ($now - $sftpTab->lastRemoteClickTime) > $doubleClickThreshold
                ) {
                    $sftpTab->lastRemoteClickPath = $path;
                    $sftpTab->lastRemoteClickTime = $now;
                    return;
                }

                // Zweiter Klick innerhalb des Zeitfensters -> als Doppelklick werten
                $sftpTab->lastRemoteClickPath = null;
                $sftpTab->lastRemoteClickTime = 0.0;

                $loadButton = new Button('Load', '');
                $loadButton->setOnClickAsync(
                    function () use ($path, &$currentPrivateKeyPath, &$selectedServerRef) {
                        if ($selectedServerRef === null || empty($currentPrivateKeyPath)) {
                            return ['error' => 'Not connected'];
                        }

                        // Copy to local variable for async context
                        $selectedServer = $selectedServerRef;

                        try {
                            $sftp = new \phpseclib3\Net\SFTP($selectedServer['ipv4']);
                            $key = \phpseclib3\Crypt\PublicKeyLoader::load(file_get_contents($currentPrivateKeyPath));

                            if (!$sftp->login('root', $key)) {
                                return ['error' => 'SFTP Login failed'];
                            }

                            $files = $sftp->nlist($path);
                            if ($files === false) {
                                return ['error' => 'Cannot read directory'];
                            }

                            $fileList = [];
                            foreach ($files as $file) {
                                if ($file === '.' || $file === '..') {
                                    continue;
                                }
                                $fullPath = rtrim($path, '/') . '/' . $file;
                                $stat = $sftp->stat($fullPath);
                                $fileList[] = [
                                    'name' => $file,
                                    'path' => $fullPath,
                                    'isDir' => ($stat['type'] ?? 0) === 2,
                                    'size' => $stat['size'] ?? 0,
                                    'mtime' => $stat['mtime'] ?? 0,
                                ];
                            }

                            return ['success' => true, 'path' => $path, 'files' => $fileList];
                        } catch (\Exception $e) {
                            return ['error' => $e->getMessage()];
                        }
                    },
                    function ($result) use ($sftpTab, $statusLabel) {
                        if (isset($result['error'])) {
                            $statusLabel->setText('SFTP Fehler: ' . $result['error']);
                            return;
                        }

                        if (isset($result['success'])) {
                            $sftpTab->remoteFileBrowser->setPath($result['path']);
                            $sftpTab->remoteFileBrowser->setFileData($result['files']);
                        }
                    },
                    function ($error) use ($statusLabel) {
                        $errorMsg = is_string($error) ? $error : 'Unknown error';
                        $statusLabel->setText('SFTP Error: ' . $errorMsg);
                    },
                );

                $loadButton->handleMouseClick(0, 0, 0);
            },
        );
    }

    private function setupSftpConnectionHandler(
        string &$currentPrivateKeyPath,
        string &$currentRemoteStartDir,
        ServerListTab $serverListTab,
        \PHPNative\Ui\Widget\TabContainer $tabContainer,
        Label $statusLabel,
    ): void {
        $sftpTab = $this;

        // Create a reference to selectedServer that we can update
        $selectedServerRef = &$serverListTab->selectedServer;

        // Set up async handler for SFTP connection (tab switch happens in success callback)
        $serverListTab->getSftpButton()->setOnClickAsync(
            function () use (&$currentPrivateKeyPath, &$currentRemoteStartDir, &$selectedServerRef) {
                if ($selectedServerRef === null) {
                    return ['error' => 'Kein Server ausgewählt'];
                }

                // Copy the selected server data to a local variable for use in async context
                $selectedServer = $selectedServerRef;

                if (empty($currentPrivateKeyPath) || !file_exists($currentPrivateKeyPath)) {
                    return ['error' => 'Private Key Pfad nicht konfiguriert oder Datei nicht gefunden'];
                }

                try {
                    $ssh = new \phpseclib3\Net\SSH2($selectedServer['ipv4']);
                    $key = \phpseclib3\Crypt\PublicKeyLoader::load(file_get_contents($currentPrivateKeyPath));

                    if (!$ssh->login('root', $key)) {
                        return ['error' => 'SSH Login fehlgeschlagen'];
                    }

                    $sftp = new \phpseclib3\Net\SFTP($selectedServer['ipv4']);
                    if (!$sftp->login('root', $key)) {
                        return ['error' => 'SFTP Login fehlgeschlagen'];
                    }

                    // Use configured start directory or fallback to root
                    $startDir = !empty($currentRemoteStartDir) ? $currentRemoteStartDir : '/';

                    // Check if start directory exists, fallback to root if not
                    if (!$sftp->is_dir($startDir)) {
                        $startDir = '/';
                    }

                    $files = $sftp->nlist($startDir);
                    if ($files === false) {
                        return ['error' => 'Kann Verzeichnis nicht lesen: ' . $startDir];
                    }

                    $fileList = [];
                    foreach ($files as $file) {
                        if ($file === '.' || $file === '..') {
                            continue;
                        }
                        $fullPath = rtrim($startDir, '/') . '/' . $file;
                        $stat = $sftp->stat($fullPath);
                        $fileList[] = [
                            'name' => $file,
                            'path' => $fullPath,
                            'isDir' => ($stat['type'] ?? 0) === 2,
                            'size' => $stat['size'] ?? 0,
                            'mtime' => $stat['mtime'] ?? 0,
                        ];
                    }

                    return [
                        'success' => true,
                        'server' => $selectedServer,
                        'files' => $fileList,
                        'path' => $startDir,
                    ];
                } catch (\Exception $e) {
                    return ['error' => 'Verbindung fehlgeschlagen: ' . $e->getMessage()];
                }
            },
            function ($result) use ($sftpTab, $tabContainer, $statusLabel) {
                if (isset($result['error'])) {
                    $statusLabel->setText('SFTP Fehler: ' . $result['error']);
                    return;
                }

                if (isset($result['success']) && $result['success']) {
                    // Switch to SFTP tab on successful connection
                    // Tab-Reihenfolge in App.php:
                    // 0 = Server, 1 = Kanban, 2 = SFTP Manager
                    $tabContainer->setActiveTab(2);

                    $sftpTab->connectionStatusLabel->setText(
                        'Verbunden mit: ' . $result['server']['name'] . ' (' . $result['server']['ipv4'] . ')',
                    );
                    $statusLabel->setText('SFTP Verbindung erfolgreich zu ' . $result['server']['name']);

                    $sftpTab->remoteFileBrowser->setPath($result['path'] ?? '/');
                    $sftpTab->remoteFileBrowser->setFileData($result['files']);
                }
            },
            function ($error) use ($statusLabel) {
                $errorMsg = is_string($error)
                    ? $error
                    : (
                        is_object($error) && method_exists($error, 'getMessage')
                            ? $error->getMessage()
                            : 'Unbekannter Fehler'
                    );
                $statusLabel->setText('SFTP Async Fehler: ' . $errorMsg);
            },
        );
    }

    public function getContainer(): Container
    {
        return $this->tab;
    }

    public function getEditModal(): Modal
    {
        return $this->editModal;
    }

    public function getFilenameModal(): Modal
    {
        return $this->filenameModal;
    }

    public function getRenameModal(): Modal
    {
        return $this->renameModal;
    }

    public function getDeleteConfirmModal(): Modal
    {
        return $this->deleteConfirmModal;
    }

    private function createEditModal(
        string &$currentPrivateKeyPath,
        ServerListTab $serverListTab,
        Label $statusLabel,
    ): void {
        // Create modal content container
        $modalContent = new Container('flex flex-col bg-white rounded-lg shadow-lg p-4 gap-3 w-[600] h-[400]');
        // Disable texture caching for modal content to allow dynamic content updates
        $modalContent->setUseTextureCache(false);

        // File path label
        $this->filePathLabel = new Label('', 'text-sm text-gray-600 font-mono');
        $modalContent->addComponent($this->filePathLabel);

        // Text editor
        $this->fileEditor = new TextArea(
            '',
            'Lade Datei...',
            'flex-1 border-2 border-gray-300 rounded p-2 bg-white text-black font-mono text-sm',
        );
        // Disable texture caching for TextArea to ensure text updates are visible
        $this->fileEditor->setUseTextureCache(false);
        $modalContent->addComponent($this->fileEditor);

        // Button container
        $buttonContainer = new Container('flex flex-row justify-end gap-2');

        // Cancel button
        $cancelButton = new Button(
            'Abbrechen',
            'px-4 py-2 bg-gray-300 text-black rounded hover:bg-gray-400',
        );
        $sftpTab = $this;
        $cancelButton->setOnClick(function () use ($sftpTab) {
            $sftpTab->editModal->setVisible(false);
        });
        $buttonContainer->addComponent($cancelButton);

        // Save button
        $saveButton = new Button('Speichern', 'px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600');
        $saveButton->setOnClick(function () use ($sftpTab, &$currentPrivateKeyPath, $serverListTab, $statusLabel) {
            $sftpTab->handleFileSave($currentPrivateKeyPath, $serverListTab, $statusLabel);
        });
        $buttonContainer->addComponent($saveButton);

        $modalContent->addComponent($buttonContainer);

        // Create modal (will be added to main container by App.php)
        $this->editModal = new Modal($modalContent);
    }

    private function handleFileEdit(
        string $path,
        array $row,
        string &$currentPrivateKeyPath,
        ServerListTab $serverListTab,
        Label $statusLabel,
    ): void {
        $this->currentEditFilePath = $path;
        $this->filePathLabel->setText('Bearbeite: ' . $path);
        $this->fileEditor->setValue('');
        $this->fileEditor->setFocused(false);
        $this->editModal->setVisible(true);

        // Reference to components for async callback
        $selectedServerRef = &$serverListTab->selectedServer;
        $sftpTab = $this;

        // Load file content asynchronously
        $loadButton = new Button('Load', '');
        $loadButton->setOnClickAsync(
            function () use ($path, &$currentPrivateKeyPath, &$selectedServerRef) {
                if ($selectedServerRef === null || empty($currentPrivateKeyPath)) {
                    return ['error' => 'Not connected'];
                }

                $selectedServer = $selectedServerRef;

                try {
                    $sftp = new \phpseclib3\Net\SFTP($selectedServer['ipv4']);
                    $key = \phpseclib3\Crypt\PublicKeyLoader::load(file_get_contents($currentPrivateKeyPath));

                    if (!$sftp->login('root', $key)) {
                        return ['error' => 'SFTP Login failed'];
                    }

                    $fileContent = $sftp->get($path);
                    if ($fileContent === false) {
                        return ['error' => 'Could not read file'];
                    }

                    return ['success' => true, 'content' => $fileContent];
                } catch (\Exception $e) {
                    return ['error' => $e->getMessage()];
                }
            },
            function ($result) use ($sftpTab, $statusLabel) {
                if (isset($result['error'])) {
                    $statusLabel->setText('Fehler beim Laden: ' . $result['error']);
                    $sftpTab->editModal->setVisible(false);
                    return;
                }

                if (isset($result['success'])) {
                    $sftpTab->fileEditor->setValue($result['content']);
                    $sftpTab->fileEditor->setFocused(true);
                    $statusLabel->setText('Datei geladen');
                }
            },
            function ($error) use ($statusLabel, $sftpTab) {
                $errorMsg = is_string($error) ? $error : 'Unknown error';
                $statusLabel->setText('Fehler: ' . $errorMsg);
                $sftpTab->editModal->setVisible(false);
            },
        );

        $loadButton->handleMouseClick(0, 0, 0);
    }

    private function handleFileSave(
        string &$currentPrivateKeyPath,
        ServerListTab $serverListTab,
        Label $statusLabel,
    ): void {
        $content = $this->fileEditor->getValue();
        $path = $this->currentEditFilePath;

        if (empty($path)) {
            $statusLabel->setText('Fehler: Kein Dateipfad');
            return;
        }

        // Reference to components for async callback
        $selectedServerRef = &$serverListTab->selectedServer;
        $sftpTab = $this;

        // Save file content asynchronously
        $saveButton = new Button('Save', '');
        $saveButton->setOnClickAsync(
            function () use ($path, $content, &$currentPrivateKeyPath, &$selectedServerRef) {
                if ($selectedServerRef === null || empty($currentPrivateKeyPath)) {
                    return ['error' => 'Not connected'];
                }

                $selectedServer = $selectedServerRef;

                try {
                    $sftp = new \phpseclib3\Net\SFTP($selectedServer['ipv4']);
                    $key = \phpseclib3\Crypt\PublicKeyLoader::load(file_get_contents($currentPrivateKeyPath));

                    if (!$sftp->login('root', $key)) {
                        return ['error' => 'SFTP Login failed'];
                    }

                    $result = $sftp->put($path, $content);
                    if ($result === false) {
                        return ['error' => 'Could not write file'];
                    }

                    return ['success' => true];
                } catch (\Exception $e) {
                    return ['error' => $e->getMessage()];
                }
            },
            function ($result) use ($sftpTab, $statusLabel, &$currentPrivateKeyPath, &$selectedServerRef) {
                if (isset($result['error'])) {
                    $statusLabel->setText('Fehler beim Speichern: ' . $result['error']);
                    return;
                }

                if (isset($result['success'])) {
                    $statusLabel->setText('Datei erfolgreich gespeichert');
                    $sftpTab->editModal->setVisible(false);

                    // Reload the current directory to show the new/updated file
                    $sftpTab->reloadCurrentDirectory($currentPrivateKeyPath, $selectedServerRef, $statusLabel);
                }
            },
            function ($error) use ($statusLabel) {
                $errorMsg = is_string($error) ? $error : 'Unknown error';
                $statusLabel->setText('Fehler: ' . $errorMsg);
            },
        );

        $saveButton->handleMouseClick(0, 0, 0);
    }

    private function handleNewFile(
        string &$currentPrivateKeyPath,
        ServerListTab $serverListTab,
        Label $statusLabel,
    ): void {
        if ($serverListTab->selectedServer === null) {
            $statusLabel->setText('Kein Server ausgewählt');
            return;
        }

        // Show filename input modal
        $this->filenameInput->setValue('neue_datei.txt');
        $this->filenameModal->setVisible(true);
    }

    private function createFilenameModal(
        string &$currentPrivateKeyPath,
        ServerListTab $serverListTab,
        Label $statusLabel,
    ): void {
        // Create modal content
        $modalContent = new Container('flex flex-col bg-white rounded-lg shadow-lg p-4 gap-3 w-96');

        // Title
        $modalContent->addComponent(new Label('Neue Datei', 'text-lg font-bold text-black'));

        // Filename input
        $this->filenameInput = new TextInput(
            'Dateiname',
            'w-full border-2 border-gray-300 rounded px-3 py-2 bg-white text-black',
        );
        $modalContent->addComponent($this->filenameInput);

        // Button container
        $buttonContainer = new Container('flex flex-row justify-end gap-2');

        // Cancel button
        $cancelButton = new Button('Abbrechen', 'px-4 py-2 bg-gray-300 text-black rounded hover:bg-gray-400');
        $sftpTab = $this;
        $cancelButton->setOnClick(function () use ($sftpTab) {
            $sftpTab->filenameModal->setVisible(false);
        });
        $buttonContainer->addComponent($cancelButton);

        // Create button
        $createButton = new Button('Erstellen', 'px-4 py-2 bg-green-600 text-white rounded hover:bg-green-700');
        $createButton->setOnClick(function () use ($sftpTab, $statusLabel) {
            $filename = trim($sftpTab->filenameInput->getValue());

            if (empty($filename)) {
                $statusLabel->setText('Dateiname darf nicht leer sein');
                return;
            }

            // Close filename modal
            $sftpTab->filenameModal->setVisible(false);

            // Create the new file with the given name
            $currentPath = $sftpTab->remoteFileBrowser->getCurrentPath();
            $newFilePath = rtrim($currentPath, '/') . '/' . $filename;

            $sftpTab->currentEditFilePath = $newFilePath;
            $sftpTab->filePathLabel->setText('Neue Datei: ' . $newFilePath);
            $sftpTab->fileEditor->setValue('');
            $sftpTab->fileEditor->setFocused(true);
            $sftpTab->editModal->setVisible(true);

            $statusLabel->setText('Neue Datei wird erstellt: ' . $filename);
        });
        $buttonContainer->addComponent($createButton);

        $modalContent->addComponent($buttonContainer);

        // Create modal
        $this->filenameModal = new Modal($modalContent);
    }

    private function reloadCurrentDirectory(
        string &$currentPrivateKeyPath,
        ?array &$selectedServerRef,
        Label $statusLabel,
    ): void {
        $path = $this->remoteFileBrowser->getCurrentPath();

        if ($selectedServerRef === null || empty($currentPrivateKeyPath)) {
            return;
        }

        $sftpTab = $this;

        // Load directory asynchronously
        $loadButton = new Button('Load', '');
        $loadButton->setOnClickAsync(
            function () use ($path, &$currentPrivateKeyPath, &$selectedServerRef) {
                if ($selectedServerRef === null || empty($currentPrivateKeyPath)) {
                    return ['error' => 'Not connected'];
                }

                $selectedServer = $selectedServerRef;

                try {
                    $sftp = new \phpseclib3\Net\SFTP($selectedServer['ipv4']);
                    $key = \phpseclib3\Crypt\PublicKeyLoader::load(file_get_contents($currentPrivateKeyPath));

                    if (!$sftp->login('root', $key)) {
                        return ['error' => 'SFTP Login failed'];
                    }

                    $files = $sftp->nlist($path);
                    if ($files === false) {
                        return ['error' => 'Cannot read directory'];
                    }

                    $fileList = [];
                    foreach ($files as $file) {
                        if ($file === '.' || $file === '..') {
                            continue;
                        }
                        $fullPath = rtrim($path, '/') . '/' . $file;
                        $stat = $sftp->stat($fullPath);
                        $fileList[] = [
                            'name' => $file,
                            'path' => $fullPath,
                            'isDir' => ($stat['type'] ?? 0) === 2,
                            'size' => $stat['size'] ?? 0,
                            'mtime' => $stat['mtime'] ?? 0,
                        ];
                    }

                    return ['success' => true, 'path' => $path, 'files' => $fileList];
                } catch (\Exception $e) {
                    return ['error' => $e->getMessage()];
                }
            },
            function ($result) use ($sftpTab, $statusLabel) {
                if (isset($result['error'])) {
                    $statusLabel->setText('Fehler beim Aktualisieren: ' . $result['error']);
                    return;
                }

                if (isset($result['success'])) {
                    $sftpTab->remoteFileBrowser->setPath($result['path']);
                    $sftpTab->remoteFileBrowser->setFileData($result['files']);
                }
            },
            function ($error) use ($statusLabel) {
                $errorMsg = is_string($error) ? $error : 'Unknown error';
                $statusLabel->setText('Fehler beim Aktualisieren: ' . $errorMsg);
            },
        );

        $loadButton->handleMouseClick(0, 0, 0);
    }

    private function handleUpload(
        string &$currentPrivateKeyPath,
        ServerListTab $serverListTab,
        Label $statusLabel,
    ): void {
        if ($this->currentLocalSelection === null) {
            $statusLabel->setText('Keine lokale Datei ausgewählt');
            return;
        }

        $localRow = $this->currentLocalSelection['row'] ?? null;
        $localPath = $this->currentLocalSelection['path'] ?? null;

        if ($localRow === null || $localPath === null) {
            $statusLabel->setText('Ungültige lokale Auswahl');
            return;
        }

        if ($serverListTab->selectedServer === null) {
            $statusLabel->setText('Kein Server ausgewählt');
            return;
        }

        if (empty($currentPrivateKeyPath) || !file_exists($currentPrivateKeyPath)) {
            $statusLabel->setText('Private Key Pfad nicht konfiguriert oder Datei nicht gefunden');
            return;
        }

        $remoteDir = $this->remoteFileBrowser->getCurrentPath();
        if ($remoteDir === '') {
            $remoteDir = '/';
        }

        // Upload-Queue inkl. Byte-Größen vorbereiten
        $this->pendingUploadQueue = $this->buildUploadQueue($localPath, $localRow, $remoteDir);
        $this->totalUploadFiles = count($this->pendingUploadQueue);
        $this->completedUploadFiles = 0;
        $this->totalUploadBytes = 0;
        $this->completedUploadBytes = 0;

        foreach ($this->pendingUploadQueue as $item) {
            $this->totalUploadBytes += (int) ($item['size'] ?? 0);
        }

        $this->transferProgressBar->setValue(0.0);
        $this->transferInfoLabel->setText(
            sprintf(
                'Upload: %d Dateien',
                $this->totalUploadFiles,
            ),
        );
        $this->transferBytesLabel->setText(
            sprintf(
                '0.00 / %.2f MB',
                $this->totalUploadBytes > 0 ? ($this->totalUploadBytes / (1024 * 1024)) : 0,
            ),
        );

        if ($this->totalUploadFiles <= 0) {
            $this->transferProgressBar->setValue(1.0);
            $this->transferInfoLabel->setText('Keine Dateien zum Hochladen');
            return;
        }

        // Referenz auf ausgewählten Server für spätere Reloads
        $this->startNextUploadTask($currentPrivateKeyPath, $serverListTab, $statusLabel);
    }

    /**
     * Lokale Upload-Statistik (Dateien/Ordner/Bytes) rekursiv berechnen.
     */
    private function calculateLocalUploadStats(string $path, array $row): array
    {
        $files = 0;
        $dirs = 0;
        $bytes = 0;

        $isDir = (bool) ($row['isDir'] ?? false);

        if (!$isDir) {
            if (is_file($path) && is_readable($path)) {
                $files = 1;
                $bytes = (int) @filesize($path);
            }
            return ['files' => $files, 'dirs' => $dirs, 'bytes' => $bytes];
        }

        // Ordner: rekursiv zählen
        $dirs++;

        $iterator = @scandir($path);
        if ($iterator === false) {
            return ['files' => $files, 'dirs' => $dirs, 'bytes' => $bytes];
        }

        foreach ($iterator as $entry) {
            if ($entry === '.' || $entry === '..') {
                continue;
            }

            $childPath = $path . DIRECTORY_SEPARATOR . $entry;

            if (is_dir($childPath)) {
                $childStats = $this->calculateLocalUploadStats($childPath, ['isDir' => true]);
                $files += $childStats['files'];
                $dirs += $childStats['dirs'];
                $bytes += $childStats['bytes'];
            } elseif (is_file($childPath) && is_readable($childPath)) {
                $files++;
                $bytes += (int) @filesize($childPath);
            }
        }

        return ['files' => $files, 'dirs' => $dirs, 'bytes' => $bytes];
    }

    /**
     * Queue für Datei-Uploads aufbauen (Datei- oder Ordner-Auswahl).
     *
     * @return array<int,array{local:string,remote:string}>
     */
    private function buildUploadQueue(string $localPath, array $row, string $remoteDir): array
    {
        $queue = [];
        $remoteBase = rtrim($remoteDir, '/');
        if ($remoteBase === '') {
            $remoteBase = '/';
        }

        $isDir = (bool) ($row['isDir'] ?? false);
        if (!$isDir) {
            $queue[] = [
                'local' => $localPath,
                'remote' => $remoteBase . '/' . basename($localPath),
                'size' => is_file($localPath) ? (int) @filesize($localPath) : 0,
            ];
            return $queue;
        }

        // Wurzelordner auf Remote
        $rootRemote = $remoteBase . '/' . basename($localPath);
        $this->collectUploadFilesRecursive($localPath, $rootRemote, $queue);

        return $queue;
    }

    /**
     * Rekursive Sammlung aller Dateien eines Ordners.
     *
     * @param array<int,array{local:string,remote:string}> $queue
     */
    private function collectUploadFilesRecursive(string $localDir, string $remoteDir, array &$queue): void
    {
        $entries = @scandir($localDir);
        if ($entries === false) {
            return;
        }

        foreach ($entries as $entry) {
            if ($entry === '.' || $entry === '..') {
                continue;
            }

            $localChild = $localDir . DIRECTORY_SEPARATOR . $entry;
            $remoteChild = rtrim($remoteDir, '/') . '/' . $entry;

            if (is_dir($localChild)) {
                $this->collectUploadFilesRecursive($localChild, $remoteChild, $queue);
            } elseif (is_file($localChild) && is_readable($localChild)) {
                $queue[] = [
                    'local' => $localChild,
                    'remote' => $remoteChild,
                    'size' => is_file($localChild) ? (int) @filesize($localChild) : 0,
                ];
            }
        }
    }

    /**
     * Nächste Datei aus der Upload-Queue hochladen und ProgressBar aktualisieren.
     */
    private function startNextUploadTask(
        string &$currentPrivateKeyPath,
        ServerListTab $serverListTab,
        Label $statusLabel,
    ): void {
        if ($this->totalUploadFiles <= 0) {
            $this->transferProgressBar->setValue(1.0);
            $this->transferInfoLabel->setText('Keine Dateien zum Hochladen');
            return;
        }

        if (empty($this->pendingUploadQueue)) {
            // Alle Dateien hochgeladen
            $this->transferProgressBar->setValue(1.0);
            $this->transferInfoLabel->setText('Upload abgeschlossen');

            $selectedServerRef = &$serverListTab->selectedServer;
            $this->reloadCurrentDirectory($currentPrivateKeyPath, $selectedServerRef, $statusLabel);
            return;
        }

        $item = array_shift($this->pendingUploadQueue);
        $localPath = $item['local'];
        $remotePath = $item['remote'];
        $fileSize = (int) ($item['size'] ?? 0);

        $selectedServerRef = &$serverListTab->selectedServer;
        $sftpTab = $this;

        $uploadAsyncButton = new Button('UploadChunk', '');
        $uploadAsyncButton->setOnClickAsync(
            function () use (&$currentPrivateKeyPath, &$selectedServerRef, $localPath, $remotePath) {
                if ($selectedServerRef === null || empty($currentPrivateKeyPath)) {
                    return ['error' => 'Not connected'];
                }

                $selectedServer = $selectedServerRef;

                try {
                    $sftp = new \phpseclib3\Net\SFTP($selectedServer['ipv4']);
                    $key = \phpseclib3\Crypt\PublicKeyLoader::load(file_get_contents($currentPrivateKeyPath));

                    if (!$sftp->login('root', $key)) {
                        return ['error' => 'SFTP Login failed'];
                    }

                    // Zielverzeichnis sicherstellen
                    $remoteDir = dirname($remotePath);
                    if (!$sftp->is_dir($remoteDir)) {
                        if (!$sftp->mkdir($remoteDir, -1, true)) {
                            return ['error' => 'Kann Remote-Verzeichnis nicht anlegen'];
                        }
                    }

                    if (!is_file($localPath) || !is_readable($localPath)) {
                        return ['error' => 'Lokale Datei ist nicht lesbar'];
                    }

                    $result = $sftp->put(
                        $remotePath,
                        $localPath,
                        \phpseclib3\Net\SFTP::SOURCE_LOCAL_FILE,
                    );
                    if ($result === false) {
                        return ['error' => 'Upload fehlgeschlagen'];
                    }

                    return ['success' => true];
                } catch (\Exception $e) {
                    return ['error' => $e->getMessage()];
                }
            },
            function ($result) use ($sftpTab, &$currentPrivateKeyPath, $serverListTab, $statusLabel, $fileSize) {
                if (isset($result['error'])) {
                    $sftpTab->transferInfoLabel->setText('Upload fehlgeschlagen: ' . $result['error']);
                    $statusLabel->setText('Fehler beim Hochladen: ' . $result['error']);
                    return;
                }

                if (isset($result['success'])) {
                    $sftpTab->completedUploadFiles++;
                    $sftpTab->completedUploadBytes += $fileSize;

                    $progress = 0.0;
                    if ($sftpTab->totalUploadBytes > 0) {
                        $progress = $sftpTab->completedUploadBytes / $sftpTab->totalUploadBytes;
                    } elseif ($sftpTab->totalUploadFiles > 0) {
                        $progress = $sftpTab->completedUploadFiles / $sftpTab->totalUploadFiles;
                    } else {
                        $progress = 1.0;
                    }

                    $sftpTab->transferProgressBar->setValue($progress);
                    $sftpTab->transferInfoLabel->setText(
                        sprintf(
                            'Upload: %d / %d Dateien',
                            $sftpTab->completedUploadFiles,
                            $sftpTab->totalUploadFiles,
                        ),
                    );
                    $sftpTab->transferBytesLabel->setText(
                        sprintf(
                            '%.2f / %.2f MB',
                            $sftpTab->completedUploadBytes > 0
                                ? ($sftpTab->completedUploadBytes / (1024 * 1024))
                                : 0,
                            $sftpTab->totalUploadBytes > 0
                                ? ($sftpTab->totalUploadBytes / (1024 * 1024))
                                : 0,
                        ),
                    );

                    // Nächste Datei starten
                    $sftpTab->startNextUploadTask($currentPrivateKeyPath, $serverListTab, $statusLabel);
                }
            },
            function ($error) use ($sftpTab, $statusLabel) {
                $errorMsg = is_string($error) ? $error : 'Unknown error';
                $sftpTab->transferInfoLabel->setText('Upload fehlgeschlagen: ' . $errorMsg);
                $statusLabel->setText('Fehler beim Hochladen: ' . $errorMsg);
            },
        );

        $uploadAsyncButton->handleMouseClick(0, 0, 0);
    }

    /**
     * Nächste Datei aus der Download-Queue holen und Fortschritt aktualisieren.
     */
    private function startNextDownloadTask(
        string &$currentPrivateKeyPath,
        ServerListTab $serverListTab,
        Label $statusLabel,
        string $localRootDir,
    ): void {
        if ($this->totalDownloadFiles <= 0) {
            $this->transferProgressBar->setValue(1.0);
            $this->transferInfoLabel->setText('Keine Dateien zum Herunterladen');
            return;
        }

        if (empty($this->pendingDownloadQueue)) {
            // Alle Dateien heruntergeladen
            $this->transferProgressBar->setValue(1.0);
            $this->transferInfoLabel->setText('Download abgeschlossen');
            $this->localFileBrowser->loadDirectory($localRootDir);
            return;
        }

        $item = array_shift($this->pendingDownloadQueue);
        $remotePath = $item['remote'];
        $localPath = $item['local'];
        $fileSize = (int) ($item['size'] ?? 0);

        $selectedServerRef = &$serverListTab->selectedServer;
        $sftpTab = $this;

        $downloadAsyncButton = new Button('DownloadChunk', '');
        $downloadAsyncButton->setOnClickAsync(
            function () use (&$currentPrivateKeyPath, &$selectedServerRef, $remotePath, $localPath) {
                if ($selectedServerRef === null || empty($currentPrivateKeyPath)) {
                    return ['error' => 'Not connected'];
                }

                $selectedServer = $selectedServerRef;

                try {
                    $sftp = new \phpseclib3\Net\SFTP($selectedServer['ipv4']);
                    $key = \phpseclib3\Crypt\PublicKeyLoader::load(file_get_contents($currentPrivateKeyPath));

                    if (!$sftp->login('root', $key)) {
                        return ['error' => 'SFTP Login failed'];
                    }

                    $localDir = dirname($localPath);
                    if (!is_dir($localDir)) {
                        if (!mkdir($localDir, 0777, true) && !is_dir($localDir)) {
                            return ['error' => 'Lokales Zielverzeichnis kann nicht erstellt werden'];
                        }
                    }

                    $result = $sftp->get($remotePath, $localPath);
                    if ($result === false) {
                        return ['error' => 'Download fehlgeschlagen'];
                    }

                    return ['success' => true];
                } catch (\Exception $e) {
                    return ['error' => $e->getMessage()];
                }
            },
            function ($result) use ($sftpTab, &$currentPrivateKeyPath, $serverListTab, $statusLabel, $localRootDir, $fileSize) {
                if (isset($result['error'])) {
                    $sftpTab->transferInfoLabel->setText('Download fehlgeschlagen: ' . $result['error']);
                    $statusLabel->setText('Fehler beim Herunterladen: ' . $result['error']);
                    return;
                }

                if (isset($result['success'])) {
                    $sftpTab->completedDownloadFiles++;
                    $sftpTab->completedDownloadBytes += $fileSize;

                    $progress = 0.0;
                    if ($sftpTab->totalDownloadBytes > 0) {
                        $progress = $sftpTab->completedDownloadBytes / $sftpTab->totalDownloadBytes;
                    } elseif ($sftpTab->totalDownloadFiles > 0) {
                        $progress = $sftpTab->completedDownloadFiles / $sftpTab->totalDownloadFiles;
                    } else {
                        $progress = 1.0;
                    }

                    $sftpTab->transferProgressBar->setValue($progress);
                    $sftpTab->transferInfoLabel->setText(
                        sprintf(
                            'Download: %d / %d Dateien',
                            $sftpTab->completedDownloadFiles,
                            $sftpTab->totalDownloadFiles,
                        ),
                    );
                    $sftpTab->transferBytesLabel->setText(
                        sprintf(
                            '%.2f / %.2f MB',
                            $sftpTab->completedDownloadBytes > 0
                                ? ($sftpTab->completedDownloadBytes / (1024 * 1024))
                                : 0,
                            $sftpTab->totalDownloadBytes > 0
                                ? ($sftpTab->totalDownloadBytes / (1024 * 1024))
                                : 0,
                        ),
                    );

                    // Nächste Datei herunterladen
                    $sftpTab->startNextDownloadTask($currentPrivateKeyPath, $serverListTab, $statusLabel, $localRootDir);
                }
            },
            function ($error) use ($sftpTab, $statusLabel) {
                $errorMsg = is_string($error) ? $error : 'Unknown error';
                $sftpTab->transferInfoLabel->setText('Download fehlgeschlagen: ' . $errorMsg);
                $statusLabel->setText('Fehler beim Herunterladen: ' . $errorMsg);
            },
        );

        $downloadAsyncButton->handleMouseClick(0, 0, 0);
    }

    private function handleDownload(
        string &$currentPrivateKeyPath,
        ServerListTab $serverListTab,
        Label $statusLabel,
    ): void {
        if ($this->currentRemoteSelection === null) {
            $statusLabel->setText('Keine Remote-Datei ausgewählt');
            return;
        }

        $remoteRow = $this->currentRemoteSelection['row'] ?? null;
        $remotePath = $this->currentRemoteSelection['path'] ?? null;

        if ($remoteRow === null || $remotePath === null) {
            $statusLabel->setText('Ungültige Remote-Auswahl');
            return;
        }

        if ($serverListTab->selectedServer === null) {
            $statusLabel->setText('Kein Server ausgewählt');
            return;
        }

        if (empty($currentPrivateKeyPath) || !file_exists($currentPrivateKeyPath)) {
            $statusLabel->setText('Private Key Pfad nicht konfiguriert oder Datei nicht gefunden');
            return;
        }

        $localDir = $this->localFileBrowser->getCurrentPath();
        if ($localDir === '') {
            $localDir = getcwd();
        }

        if (!is_dir($localDir) || !is_writable($localDir)) {
            $statusLabel->setText('Lokales Verzeichnis ist nicht beschreibbar');
            return;
        }

        $this->transferProgressBar->setValue(0.0);
        $this->transferInfoLabel->setText('Download wird vorbereitet …');

        // Async-Scan der Remote-Struktur, um eine Download-Queue aufzubauen
        $selectedServerRef = &$serverListTab->selectedServer;
        $sftpTab = $this;

        $scanButton = new Button('ScanDownload', '');
        $scanButton->setOnClickAsync(
            function () use (&$currentPrivateKeyPath, &$selectedServerRef, $remotePath, $remoteRow, $localDir) {
                if ($selectedServerRef === null || empty($currentPrivateKeyPath)) {
                    return ['error' => 'Not connected'];
                }

                $selectedServer = $selectedServerRef;

                try {
                    $sftp = new \phpseclib3\Net\SFTP($selectedServer['ipv4']);
                    $key = \phpseclib3\Crypt\PublicKeyLoader::load(file_get_contents($currentPrivateKeyPath));

                    if (!$sftp->login('root', $key)) {
                        return ['error' => 'SFTP Login failed'];
                    }

                    $queue = [];
                    $files = 0;
                    $dirs = 0;
                    $totalBytes = 0;

                    $isDir = (bool) ($remoteRow['isDir'] ?? false);
                    if (!$isDir) {
                        $stat = $sftp->stat($remotePath);
                        $size = (int) ($stat['size'] ?? 0);
                        $queue[] = [
                            'remote' => $remotePath,
                            'local' => rtrim($localDir, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . basename($remotePath),
                            'size' => $size,
                        ];
                        $files = 1;
                        $totalBytes = $size;
                    } else {
                        $rootLocal = rtrim($localDir, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . basename($remotePath);

                        $collect = null;
                        $collect = function (string $srcDir, string $dstDir) use (&$collect, $sftp, &$queue, &$files, &$dirs, &$totalBytes) {
                            $dirs++;

                            $entries = $sftp->nlist($srcDir);
                            if ($entries === false) {
                                return;
                            }

                            foreach ($entries as $entry) {
                                if ($entry === '.' || $entry === '..') {
                                    continue;
                                }

                                $remoteChild = rtrim($srcDir, '/') . '/' . $entry;
                                $localChild = rtrim($dstDir, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $entry;

                                $stat = $sftp->stat($remoteChild);
                                $isDirChild = ($stat['type'] ?? 0) === 2;

                                if ($isDirChild) {
                                    $collect($remoteChild, $localChild);
                                } else {
                                    $size = (int) ($stat['size'] ?? 0);
                                    $queue[] = [
                                        'remote' => $remoteChild,
                                        'local' => $localChild,
                                        'size' => $size,
                                    ];
                                    $files++;
                                    $totalBytes += $size;
                                }
                            }
                        };

                        $collect($remotePath, $rootLocal);
                    }

                    return [
                        'success' => true,
                        'queue' => $queue,
                        'files' => $files,
                        'dirs' => $dirs,
                        'localDir' => $localDir,
                        'totalBytes' => $totalBytes,
                    ];
                } catch (\Exception $e) {
                    return ['error' => $e->getMessage()];
                }
            },
            function ($result) use ($sftpTab, $statusLabel, &$currentPrivateKeyPath, $serverListTab) {
                if (isset($result['error'])) {
                    $statusLabel->setText('Fehler beim Vorbereiten des Downloads: ' . $result['error']);
                    $sftpTab->transferInfoLabel->setText('Download fehlgeschlagen');
                    return;
                }

                if (!isset($result['success']) || !$result['success']) {
                    $statusLabel->setText('Unbekannter Fehler beim Vorbereiten des Downloads');
                    $sftpTab->transferInfoLabel->setText('Download fehlgeschlagen');
                    return;
                }

                $queue = $result['queue'] ?? [];
                $files = (int) ($result['files'] ?? 0);
                $dirs = (int) ($result['dirs'] ?? 0);
                $totalBytes = (int) ($result['totalBytes'] ?? 0);

                $sftpTab->pendingDownloadQueue = $queue;
                $sftpTab->totalDownloadFiles = count($queue);
                $sftpTab->completedDownloadFiles = 0;
                $sftpTab->totalDownloadBytes = $totalBytes;
                $sftpTab->completedDownloadBytes = 0;

                if ($sftpTab->totalDownloadFiles <= 0) {
                    $sftpTab->transferProgressBar->setValue(1.0);
                    $sftpTab->transferInfoLabel->setText('Keine Dateien zum Herunterladen');
                    $sftpTab->transferBytesLabel->setText('');
                    return;
                }

                $sftpTab->transferProgressBar->setValue(0.0);
                $sftpTab->transferInfoLabel->setText(
                    sprintf(
                        'Download: %d Dateien, %d Ordner',
                        $files,
                        $dirs,
                    ),
                );
                $sftpTab->transferBytesLabel->setText(
                    sprintf(
                        '0.00 / %.2f MB',
                        $totalBytes > 0 ? ($totalBytes / (1024 * 1024)) : 0,
                    ),
                );

                $localDir = $result['localDir'] ?? '';
                $sftpTab->startNextDownloadTask($currentPrivateKeyPath, $serverListTab, $statusLabel, $localDir);
            },
            function ($error) use ($sftpTab, $statusLabel) {
                $errorMsg = is_string($error) ? $error : 'Unknown error';
                $statusLabel->setText('Fehler beim Vorbereiten des Downloads: ' . $errorMsg);
                $sftpTab->transferInfoLabel->setText('Download fehlgeschlagen');
            },
        );

        $scanButton->handleMouseClick(0, 0, 0);
    }

    private function createRenameModal(
        string &$currentPrivateKeyPath,
        ServerListTab $serverListTab,
        Label $statusLabel,
    ): void {
        // Create modal content
        $modalContent = new Container('flex flex-col bg-white rounded-lg shadow-lg p-4 gap-3 w-96');

        // Title
        $modalContent->addComponent(new Label('Umbenennen', 'text-lg font-bold text-black'));

        // Path info
        $this->renamePathLabel = new Label('', 'text-xs text-gray-600 font-mono break-words');
        $modalContent->addComponent($this->renamePathLabel);

        // Filename input
        $this->renameInput = new TextInput('Neuer Name', 'w-full border-2 border-gray-300 rounded px-3 py-2 bg-white text-black');
        $modalContent->addComponent($this->renameInput);

        // Button container
        $buttonContainer = new Container('flex flex-row justify-end gap-2');

        // Cancel button
        $cancelButton = new Button('Abbrechen', 'px-4 py-2 bg-gray-300 text-black rounded hover:bg-gray-400');
        $sftpTab = $this;
        $cancelButton->setOnClick(function () use ($sftpTab) {
            $sftpTab->renameModal->setVisible(false);
        });
        $buttonContainer->addComponent($cancelButton);

        // Rename button
        $renameButton = new Button('Umbenennen', 'px-4 py-2 bg-amber-600 text-white rounded hover:bg-amber-700');
        $renameButton->setOnClick(function () use ($sftpTab, &$currentPrivateKeyPath, $serverListTab, $statusLabel) {
            $newFilename = trim($sftpTab->renameInput->getValue());

            if (empty($newFilename)) {
                $statusLabel->setText('Dateiname darf nicht leer sein');
                return;
            }

            $oldPath = $sftpTab->currentRenameFilePath;
            $separator = $sftpTab->currentRenameMode === 'local' ? DIRECTORY_SEPARATOR : '/';
            $directory = $sftpTab->normalizeDirectory(dirname($oldPath), $separator);
            $newPath = $sftpTab->joinPath($directory, $newFilename, $separator);

            // Close rename modal
            $sftpTab->renameModal->setVisible(false);

            if ($sftpTab->currentRenameMode === 'local') {
                $succeeded = @rename($oldPath, $newPath);
                if ($succeeded === false) {
                    $statusLabel->setText('Lokales Umbenennen fehlgeschlagen');
                    return;
                }

                $statusLabel->setText('Lokal umbenannt: ' . basename($newPath));
                $sftpTab->localFileBrowser->loadDirectory($directory);
                return;
            }

            // Perform rename via SFTP
            $selectedServerRef = &$serverListTab->selectedServer;

            $renameAsyncButton = new Button('Rename', '');
            $renameAsyncButton->setOnClickAsync(
                function () use ($oldPath, $newPath, &$currentPrivateKeyPath, &$selectedServerRef) {
                    if ($selectedServerRef === null || empty($currentPrivateKeyPath)) {
                        return ['error' => 'Not connected'];
                    }

                    $selectedServer = $selectedServerRef;

                    try {
                        $sftp = new \phpseclib3\Net\SFTP($selectedServer['ipv4']);
                        $key = \phpseclib3\Crypt\PublicKeyLoader::load(file_get_contents($currentPrivateKeyPath));

                        if (!$sftp->login('root', $key)) {
                            return ['error' => 'SFTP Login failed'];
                        }

                        $result = $sftp->rename($oldPath, $newPath);
                        if ($result === false) {
                            return ['error' => 'Could not rename file'];
                        }

                        return ['success' => true];
                    } catch (\Exception $e) {
                        return ['error' => $e->getMessage()];
                    }
                },
                function ($result) use ($sftpTab, $statusLabel, &$currentPrivateKeyPath, &$selectedServerRef) {
                    if (isset($result['error'])) {
                        $statusLabel->setText('Fehler beim Umbenennen: ' . $result['error']);
                        return;
                    }

                    if (isset($result['success'])) {
                        $statusLabel->setText('Datei erfolgreich umbenannt');
                        $sftpTab->reloadCurrentDirectory($currentPrivateKeyPath, $selectedServerRef, $statusLabel);
                    }
                },
                function ($error) use ($statusLabel) {
                    $errorMsg = is_string($error) ? $error : 'Unknown error';
                    $statusLabel->setText('Fehler beim Umbenennen: ' . $errorMsg);
                },
            );

            $renameAsyncButton->handleMouseClick(0, 0, 0);
        });
        $buttonContainer->addComponent($renameButton);

        $modalContent->addComponent($buttonContainer);

        // Create modal
        $this->renameModal = new Modal($modalContent);
    }

    private function createDeleteConfirmModal(
        string &$currentPrivateKeyPath,
        ServerListTab $serverListTab,
        Label $statusLabel,
    ): void {
        // Create modal content
        $modalContent = new Container('flex flex-col bg-white rounded-lg shadow-lg p-4 gap-3 w-96');

        // Title
        $modalContent->addComponent(new Label('Datei löschen', 'text-lg font-bold text-black'));

        // Confirmation message
        $this->deleteConfirmLabel = new Label(
            'Möchten Sie diese Datei wirklich löschen?',
            'text-sm text-gray-700',
        );
        $modalContent->addComponent($this->deleteConfirmLabel);

        // Button container
        $buttonContainer = new Container('flex flex-row justify-end gap-2');

        // Cancel button
        $cancelButton = new Button('Abbrechen', 'px-4 py-2 bg-gray-300 text-black rounded hover:bg-gray-400');
        $sftpTab = $this;
        $cancelButton->setOnClick(function () use ($sftpTab) {
            $sftpTab->deleteConfirmModal->setVisible(false);
        });
        $buttonContainer->addComponent($cancelButton);

        // Delete button
        $deleteButton = new Button('Löschen', 'px-4 py-2 bg-red-600 text-white rounded hover:bg-red-700');
        $deleteButton->setOnClick(function () use ($sftpTab, &$currentPrivateKeyPath, $serverListTab, $statusLabel) {
            $filePath = $sftpTab->currentDeleteFilePath;

            // Close delete modal
            $sftpTab->deleteConfirmModal->setVisible(false);

            // Perform delete via SFTP
            $selectedServerRef = &$serverListTab->selectedServer;

            $deleteAsyncButton = new Button('Delete', '');
            $deleteAsyncButton->setOnClickAsync(
                function () use ($filePath, &$currentPrivateKeyPath, &$selectedServerRef) {
                    if ($selectedServerRef === null || empty($currentPrivateKeyPath)) {
                        return ['error' => 'Not connected'];
                    }

                    $selectedServer = $selectedServerRef;

                    try {
                        $sftp = new \phpseclib3\Net\SFTP($selectedServer['ipv4']);
                        $key = \phpseclib3\Crypt\PublicKeyLoader::load(file_get_contents($currentPrivateKeyPath));

                        if (!$sftp->login('root', $key)) {
                            return ['error' => 'SFTP Login failed'];
                        }

                        $result = $sftp->delete($filePath);
                        if ($result === false) {
                            return ['error' => 'Could not delete file'];
                        }

                        return ['success' => true];
                    } catch (\Exception $e) {
                        return ['error' => $e->getMessage()];
                    }
                },
                function ($result) use ($sftpTab, $statusLabel, &$currentPrivateKeyPath, &$selectedServerRef) {
                    if (isset($result['error'])) {
                        $statusLabel->setText('Fehler beim Löschen: ' . $result['error']);
                        return;
                    }

                    if (isset($result['success'])) {
                        $statusLabel->setText('Datei erfolgreich gelöscht');
                        $sftpTab->reloadCurrentDirectory($currentPrivateKeyPath, $selectedServerRef, $statusLabel);
                    }
                },
                function ($error) use ($statusLabel) {
                    $errorMsg = is_string($error) ? $error : 'Unknown error';
                    $statusLabel->setText('Fehler beim Löschen: ' . $errorMsg);
                },
            );

            $deleteAsyncButton->handleMouseClick(0, 0, 0);
        });
        $buttonContainer->addComponent($deleteButton);

        $modalContent->addComponent($buttonContainer);

        // Create modal
        $this->deleteConfirmModal = new Modal($modalContent);
    }

    private function handleFileRename(
        string $path,
        array $row,
        string &$currentPrivateKeyPath,
        ServerListTab $serverListTab,
        Label $statusLabel,
    ): void {
        if ($serverListTab->selectedServer === null) {
            $statusLabel->setText('Kein Server ausgewählt');
            return;
        }

        $this->currentRenameMode = 'remote';
        $this->currentRenameFilePath = $path;
        $filename = basename($path);
        $this->renameInput->setValue($filename);
        $this->renamePathLabel->setText('Remote: ' . $path);
        $this->renameModal->setVisible(true);
    }

    private function handleLocalRename(string $path, array $row, Label $statusLabel): void
    {
        if (!file_exists($path)) {
            $statusLabel->setText('Lokale Datei/Ordner nicht gefunden');
            return;
        }

        $this->currentRenameMode = 'local';
        $this->currentRenameFilePath = $path;
        $this->renameInput->setValue(basename($path));
        $this->renamePathLabel->setText('Lokal: ' . $path);
        $this->renameModal->setVisible(true);
    }

    private function handleFileDelete(
        string $path,
        array $row,
        string &$currentPrivateKeyPath,
        ServerListTab $serverListTab,
        Label $statusLabel,
    ): void {
        if ($serverListTab->selectedServer === null) {
            $statusLabel->setText('Kein Server ausgewählt');
            return;
        }

        $this->currentDeleteFilePath = $path;
        $filename = basename($path);
        $this->deleteConfirmLabel->setText('Möchten Sie die Datei "' . $filename . '" wirklich löschen?');
        $this->deleteConfirmModal->setVisible(true);
    }

    private function normalizeDirectory(string $directory, string $separator): string
    {
        $normalized = rtrim($directory, $separator);
        if ($normalized === '') {
            return $separator;
        }

        return $normalized;
    }

    private function joinPath(string $directory, string $filename, string $separator): string
    {
        if ($directory === $separator) {
            return $directory . $filename;
        }

        return $directory . $separator . $filename;
    }
}
