<?php

namespace ServerManager\UI;

use PHPNative\Async\TaskManager;
use PHPNative\Framework\Settings;
use PHPNative\Tailwind\Data\Icon as IconName;
use PHPNative\Ui\Widget\Button;
use PHPNative\Ui\Widget\Checkbox;
use PHPNative\Ui\Widget\Container;
use PHPNative\Ui\Widget\Icon;
use PHPNative\Ui\Widget\Label;
use PHPNative\Ui\Widget\TabContainer;
use PHPNative\Ui\Widget\TextInput;
use PHPNative\Ui\Widget\VirtualListView;
use ServerManager\Services\HetznerService;
use ServerManager\UI\KanbanTab;
use ServerManager\UI\LoadingIndicator;

class ServerListTab
{
    private Settings $settings;
    private ?KanbanTab $kanbanTab;
    private Container $tab;
    private VirtualListView $table;
    private TextInput $searchInput;
    private Label $statusLabel;
    private Button $refreshButton;
    private Button $sftpButton;
    private Button $sshTerminalButton;

    public array $currentServerData = [];
    public ?array $selectedServer = null;

    private Label $detailId;
    private Label $detailName;
    private Label $detailStatus;
    private Label $detailType;
    private Label $detailIpv4;
    private Container $detailDomainsContainer;
    private Container $detailSshKeysContainer;
    private LoadingIndicator $loadingIndicator;
    private TextInput $serverApiKeyInput;
    private TextInput $borgmaticPassphraseInput;
    private Container $todoListContainer;
    private TextInput $todoInput;
    private array $currentServerTodos = [];
    private ?int $currentServerId = null;

    public function __construct(
        string &$apiKey,
        string &$privateKeyPath,
        TabContainer $tabContainer,
        Label $statusLabel,
        Settings $settings,
        ?KanbanTab $kanbanTab = null,
    ) {
        $this->settings = $settings;
        $this->kanbanTab = $kanbanTab;
        $this->statusLabel = $statusLabel;
        $currentApiKey = &$apiKey;
        $currentPrivateKeyPath = &$privateKeyPath;

        // Create main tab container
        $this->tab = new Container('flex flex-row p-4 gap-4');

        // Left side: Table with search and refresh
        $leftSide = new Container('flex flex-col gap-2 flex-1');

        // Header row with refresh button and loading indicator on the right
        $headerRow = new Container('flex flex-row items-center gap-2');

        // Refresh button
        $this->refreshButton = new Button(
            'Server aktualisieren',
            'flex shadow-lg/50 flex-row gap-2 px-4 py-2 bg-blue-600 rounded hover:bg-blue-700',
            null,
            'text-white',
        );
        $refreshIcon = new Icon(IconName::sync, 16, 'text-white');
        $this->refreshButton->setIcon($refreshIcon);
        $headerRow->addComponent($this->refreshButton);

        // Button to refresh selected servers only
        $refreshSelectedButton = new Button(
            'Ausgewählte aktualisieren',
            'px-3 shadow-lg/50 py-2 bg-green-600 rounded hover:bg-green-700',
            null,
            'text-white',
        );
        $refreshSelectedIcon = new Icon(IconName::sync, 16, 'text-white');
        $refreshSelectedButton->setIcon($refreshSelectedIcon);
        $headerRow->addComponent($refreshSelectedButton);

        // Bulk action buttons for selected servers
        $rebootButton = new Button(
            'Reboot ausgewählte',
            'px-3 shadow-lg/50 py-2 bg-red-600 rounded hover:bg-red-700',
            null,
            'text-white',
        );
        $updateButton = new Button(
            'Update ausgewählte',
            'px-3 shadow-lg/50 hover:shadow-red-600 py-2 bg-amber-600 rounded hover:bg-amber-700',
            null,
            'text-white',
        );
        $headerRow->addComponent($rebootButton);
        $headerRow->addComponent($updateButton);

        // Loading indicator (top-right in the server tab header)
        $this->loadingIndicator = new LoadingIndicator('ml-auto');
        $headerRow->addComponent($this->loadingIndicator);

        $leftSide->addComponent($headerRow);

        // Search input
        $this->searchInput = new TextInput(
            'Suche...',
            'w-full border border-gray-300 rounded px-3 py-2 bg-white text-black mb-2',
        );
        $leftSide->addComponent($this->searchInput);

        // Table container with header and virtual list
        $tableContainer = new Container('flex flex-col flex-1 border border-gray-300 rounded');

        // Table header
        $headerContainer = new Container('flex flex-row w-full bg-gray-200 border-b-2 border-gray-400');
        $columns = [
            [
                'key' => 'selected',
                'title' => '',
                'width' => 40,
                'render' => [$this, 'renderSelectCell'],
            ],
            ['key' => 'id', 'title' => 'ID', 'width' => 100],
            [
                'key' => 'tasks_indicator',
                'title' => '',
                'width' => 40,
                'render' => [$this, 'renderTasksIndicatorCell'],
            ],
            ['key' => 'name', 'title' => 'Name'],
            ['key' => 'status', 'title' => 'Status', 'width' => 90],
            ['key' => 'type', 'title' => 'Typ', 'width' => 80],
            ['key' => 'ipv4', 'title' => 'IPv4', 'width' => 150],
            [
                'key' => 'docker_status',
                'title' => 'Docker',
                'width' => 50,
                'render' => [$this, 'renderDockerStatusCell'],
            ],
            [
                'key' => 'docker_running',
                'title' => 'R',
                'width' => 50,
                'render' => [$this, 'renderDockerRunningCell'],
            ],
            [
                'key' => 'os_version',
                'title' => 'Ubuntu',
                'width' => 180,
                'render' => [$this, 'renderOsVersionCell'],
            ],
            ['key' => 'release', 'title' => 'Release', 'width' => 140],
            [
                'key' => 'ssh_keys_count',
                'title' => 'SSH Keys',
                'width' => 80,
                'render' => [$this, 'renderSshKeysCell'],
            ],
            [
                'key' => 'root',
                'title' => 'Root',
                'width' => 50,
                'render' => [$this, 'renderRootCell'],
            ],
            [
                'key' => 'data',
                'title' => 'Data',
                'width' => 50,
                'render' => [$this, 'renderDataCell'],
            ],
            [
                'key' => 'needs_reboot',
                'title' => 'Neustart',
                'width' => 100,
                'render' => [$this, 'renderNeedsRebootCell'],
            ],
            [
                'key' => 'updates_available',
                'title' => 'Updates',
                'width' => 100,
                'render' => [$this, 'renderUpdatesCell'],
            ],
            [
                'key' => 'last_backup',
                'title' => 'Letztes Backup',
                'width' => 180,
                'render' => [$this, 'renderLastBackupCell'],
            ],
        ];

        // Build header cells
        foreach ($columns as $column) {
            $title = $column['title'] ?? '';
            $width = $column['width'] ?? null;

            $style = 'px-4 py-2 text-black font-bold border-r border-gray-300';
            if ($width) {
                $style .= ' w-' . (int) ($width / 4);
            } else {
                $style .= ' flex-1';
            }

            $headerLabel = new Label($title, $style);
            $headerContainer->addComponent($headerLabel);
        }
        $tableContainer->addComponent($headerContainer);

        // Virtual List View (Performance-optimized)
        $this->table = new VirtualListView('flex-1 bg-white');
        $this->table->setColumns($columns);

        // Load initial test data
        $this->currentServerData = HetznerService::generateTestData();
        $this->table->setData($this->currentServerData);

        $tableContainer->addComponent($this->table);
        $leftSide->addComponent($tableContainer);

        // Right side: Detail panel
        $detailPanel = new Container(
            'flex flex-col gap-3 w-120 bg-white border-2 border-gray-300 rounded p-4 overflow-y-auto',
        );
        $detailTitle = new Label('Server Details', 'text-xl font-bold text-black mb-2');
        $detailPanel->addComponent($detailTitle);

        $this->detailId = new Label('-', 'text-sm text-gray-900 font-mono');
        $this->detailName = new Label('-', 'text-lg font-semibold text-black');
        $this->detailStatus = new Label('-', 'text-sm text-gray-700');
        $this->detailType = new Label('-', 'text-sm text-gray-700');
        $this->detailIpv4 = new Label('-', 'text-sm text-gray-700 font-mono');

        $detailPanel->addComponent(new Label('ID:', 'text-xs text-gray-500'));
        $detailPanel->addComponent($this->detailId);
        $detailPanel->addComponent(new Label('Name:', 'text-xs text-gray-500 mt-2'));
        $detailPanel->addComponent($this->detailName);
        $detailPanel->addComponent(new Label('Status:', 'text-xs text-gray-500 mt-2'));
        $detailPanel->addComponent($this->detailStatus);
        $detailPanel->addComponent(new Label('Typ:', 'text-xs text-gray-500 mt-2'));
        $detailPanel->addComponent($this->detailType);
        $detailPanel->addComponent(new Label('IPv4:', 'text-xs text-gray-500 mt-2'));
        $detailPanel->addComponent($this->detailIpv4);

        // Domains list
        $detailPanel->addComponent(new Label('Domains:', 'text-xs text-gray-500 mt-2'));
        $this->detailDomainsContainer = new Container('flex flex-col gap-1');
        $detailPanel->addComponent($this->detailDomainsContainer);

        // SSH Keys list
        $detailPanel->addComponent(new Label('SSH Keys:', 'text-xs text-gray-500 mt-2'));
        $this->detailSshKeysContainer = new Container('flex flex-col gap-1');
        $detailPanel->addComponent($this->detailSshKeysContainer);

        // SFTP Manager Button (handler will be set by SftpManagerTab)
        $this->sftpButton = new Button(
            'SFTP Manager öffnen',
            'w-full rounded-md bg-blue-500 px-3 py-2 text-sm font-semibold shadow-lg shadow-blue-500/50 focus:outline-none flex flex-row gap-2',
            null,
            'text-white',
        );
        $sftpIcon = new Icon(IconName::folder, 16, 'text-white');
        $this->sftpButton->setIcon($sftpIcon);

        $detailPanel->addComponent($this->sftpButton);

        // SSH Terminal Button
        $this->sshTerminalButton = new Button(
            'SSH Terminal öffnen',
            'w-full border border-gray-300 rounded px-3 py-2 flex shadow-lg/100 shadow-lime-300 flex-row gap-2 bg-lime-300 text-black mb-2',
            null,
            'text-black',
        );
        $sshTerminalIcon = new Icon(IconName::terminal, 16, 'text-black');
        $this->sshTerminalButton->setIcon($sshTerminalIcon);

        $serverListTab = $this;
        $this->sshTerminalButton->setOnClick(function () use ($serverListTab, &$currentPrivateKeyPath) {
            if ($serverListTab->selectedServer === null) {
                $serverListTab->statusLabel->setText('Kein Server ausgewählt');
                return;
            }

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

            $host = $serverListTab->selectedServer['ipv4'];
            $keyPath = escapeshellarg($currentPrivateKeyPath);
            $sshCommand = "ssh -i {$keyPath} root@{$host}";

            $terminals = [
                'alacritty -e ' . $sshCommand,
                'gnome-terminal -- ' . $sshCommand,
                'konsole -e ' . $sshCommand,
                'xterm -e ' . $sshCommand,
                'x-terminal-emulator -e ' . $sshCommand,
            ];

            $opened = false;
            foreach ($terminals as $terminalCmd) {
                exec($terminalCmd . ' > /dev/null 2>&1 &', $output, $returnCode);
                if ($returnCode === 0) {
                    $opened = true;
                    $serverListTab->statusLabel->setText(
                        'SSH Terminal geöffnet für ' . $serverListTab->selectedServer['name'],
                    );
                    break;
                }
            }

            if (!$opened) {
                $serverListTab->statusLabel->setText('Konnte kein Terminal öffnen. SSH Befehl: ' . $sshCommand);
            }
        });

        $detailPanel->addComponent($this->sshTerminalButton);

        // Per-server API key and TODOs
        $detailPanel->addComponent(new Label('Server API Key:', 'text-xs text-gray-500 mt-2'));
        $this->serverApiKeyInput = new TextInput(
            'Server API Key',
            'w-full border border-gray-300 rounded px-3 py-2 bg-white text-black',
        );
        $detailPanel->addComponent($this->serverApiKeyInput);

        $detailPanel->addComponent(new Label('Borgmatic Passphrase:', 'text-xs text-gray-500 mt-2'));
        $this->borgmaticPassphraseInput = new TextInput(
            'Borgmatic Passphrase',
            'w-full border border-gray-300 rounded px-3 py-2 bg-white text-black',
        );
        $detailPanel->addComponent($this->borgmaticPassphraseInput);

        $saveServerSettingsButton = new Button(
            'Server-Einstellungen speichern',
            'mt-1 px-3 py-2 bg-green-600 rounded hover:bg-green-700',
            null,
            'text-white',
        );
        $detailPanel->addComponent($saveServerSettingsButton);

        $detailPanel->addComponent(new Label('Tasks für diesen Server:', 'text-xs text-gray-500 mt-3'));
        $this->todoListContainer = new Container('flex flex-col gap-1');
        $detailPanel->addComponent($this->todoListContainer);

        $todoInputRow = new Container('flex flex-row gap-2 mt-1');
        $this->todoInput = new TextInput(
            'Neue Task...',
            'flex-1 border border-gray-300 rounded px-3 py-2 bg-white text-black',
        );
        $addTodoButton = new Button('+', 'px-3 py-2 bg-blue-600 rounded hover:bg-blue-700', null, 'text-white');
        $todoInputRow->addComponent($this->todoInput);
        $todoInputRow->addComponent($addTodoButton);
        $detailPanel->addComponent($todoInputRow);

        $this->tab->addComponent($leftSide);
        $this->tab->addComponent($detailPanel);

        // Setup event handlers
        $this->setupEventHandlers(
            $currentApiKey,
            $currentPrivateKeyPath,
            $refreshSelectedButton,
            $rebootButton,
            $updateButton,
            $saveServerSettingsButton,
            $addTodoButton,
        );
    }

    private function setupEventHandlers(
        string &$currentApiKey,
        string &$currentPrivateKeyPath,
        Button $refreshSelectedButton,
        Button $rebootButton,
        Button $updateButton,
        Button $saveServerSettingsButton,
        Button $addTodoButton,
    ): void {
        // Table row selection
        $serverListTab = $this;
        $this->table->setOnRowSelect(function ($index, $row) use ($serverListTab) {
            if ($row) {
                $serverListTab->statusLabel->setText("Server: {$row['name']} - {$row['status']} ({$row['ipv4']})");

                $serverListTab->detailId->setText("#{$row['id']}");
                $serverListTab->detailName->setText($row['name']);
                $serverListTab->detailStatus->setText($row['status']);
                $serverListTab->detailType->setText($row['type']);
                $serverListTab->detailIpv4->setText($row['ipv4']);

                // Load per-server settings (API key, todos)
                $serverId = $row['id'] ?? null;
                $serverListTab->currentServerId = is_numeric($serverId) ? (int) $serverId : null;

                if ($serverListTab->currentServerId !== null) {
                    $settingsKeyBase = 'servers.' . $serverListTab->currentServerId;
                    $apiKey = $serverListTab->settings->get($settingsKeyBase . '.api_key', '');
                    $borgmaticPassphrase = $serverListTab->settings->get(
                        $settingsKeyBase . '.borgmatic_passphrase',
                        '',
                    );

                    $serverListTab->serverApiKeyInput->setValue($apiKey);
                    $serverListTab->borgmaticPassphraseInput->setValue($borgmaticPassphrase);
                    $serverListTab->loadServerTasks();
                } else {
                    $serverListTab->serverApiKeyInput->setValue('');
                    $serverListTab->borgmaticPassphraseInput->setValue('');
                    $serverListTab->currentServerTodos = [];
                    $serverListTab->renderTodoList();
                }

                $domains = $row['domains'] ?? [];
                $serverListTab->updateDomainDetails(is_array($domains) ? $domains : []);

                $sshKeys = $row['ssh_keys'] ?? [];
                $serverListTab->updateSshKeysDetails(is_array($sshKeys) ? $sshKeys : []);

                $serverListTab->selectedServer = $row;
            }
        });

        // Search functionality
        $this->searchInput->setOnChange(function ($value) use ($serverListTab) {
            $searchTerm = strtolower(trim($value));

            if (empty($searchTerm)) {
                $serverListTab->table->updateData($serverListTab->currentServerData);
            } else {
                $filteredData = array_filter($serverListTab->currentServerData, function ($row) use ($searchTerm) {
                    // Search in server name
                    if (str_contains(strtolower($row['name']), $searchTerm)) {
                        return true;
                    }

                    // Search in domains
                    $domains = $row['domains'] ?? [];
                    if (
                        is_array($domains)
                        && count(array_filter($domains, function ($item) use ($searchTerm) {
                            return str_contains(strtolower($item), $searchTerm);
                        }))
                    ) {
                        return true;
                    }

                    // Search in SSH keys
                    $sshKeys = $row['ssh_keys'] ?? [];
                    if (
                        is_array($sshKeys)
                        && count(array_filter($sshKeys, function ($item) use ($searchTerm) {
                            return str_contains(strtolower($item), $searchTerm);
                        }))
                    ) {
                        return true;
                    }

                    return false;
                });
                $serverListTab->table->updateData(array_values($filteredData));
            }
        });

        // Refresh button - use TaskManager directly so we can control the loading indicator
        $this->refreshButton->setOnClick(function () use (&$currentApiKey, $serverListTab, &$currentPrivateKeyPath) {
            $serverListTab->loadingIndicator->setLoading(true);

            $task = TaskManager::getInstance()->runAsync(function () use (&$currentApiKey) {
                try {
                    if (empty($currentApiKey)) {
                        return ['error' => 'Kein API-Key konfiguriert'];
                    }

                    $hetznerClient = new \LKDev\HetznerCloud\HetznerAPIClient($currentApiKey);
                    $servers = [];

                    foreach ($hetznerClient->servers()->all() as $server) {
                        $servers[] = [
                            'id' => $server->id,
                            'name' => $server->name,
                            'status' => $server->status,
                            'type' => $server->serverType->name,
                            'ipv4' => $server->publicNet->ipv4->ip,
                            'docker_status' => 'pending',
                            'domains' => [],
                        ];
                    }

                    return [
                        'success' => true,
                        'servers' => $servers,
                        'count' => count($servers),
                    ];
                } catch (\Exception $e) {
                    return ['error' => 'Exception: ' . $e->getMessage()];
                }
            });

            $task->onComplete(function ($result) use (&$serverListTab, &$currentPrivateKeyPath) {
                if (is_array($result)) {
                    if (isset($result['error'])) {
                        $serverListTab->statusLabel->setText('Fehler: ' . $result['error']);
                        echo "Error: {$result['error']}\n";
                    } elseif (isset($result['success'], $result['servers'])) {
                        // Basisdaten setzen, Docker-Status initial auf "pending"
                        $serverListTab->currentServerData = array_map(static fn($row) => array_merge([
                            'docker_status' => 'pending',
                            'docker_running' => 'pending',
                            'docker' => null,
                            'docker_error' => null,
                            'needs_reboot' => 'unbekannt',
                            'updates_available' => 'unbekannt',
                            'os_version' => 'unbekannt',
                            'release' => 'unbekannt',
                            'root' => 'unbekannt',
                            'data' => 'unbekannt',
                            'last_backup' => 'unbekannt',
                            'ssh_keys' => [],
                        ], $row), $result['servers']);

                        $serverListTab->table->updateData($serverListTab->currentServerData);
                        $serverListTab->statusLabel->setText('Server geladen: ' . $result['count'] . ' gefunden');

                        // Kanban-Board aktualisieren, damit Servernamen in den Karten up-to-date sind
                        if ($serverListTab->kanbanTab !== null) {
                            $serverListTab->kanbanTab->refresh();
                        }

                        if (function_exists('desktop_notify')) {
                            desktop_notify(
                                'Serverliste aktualisiert',
                                'Es wurden ' . $result['count'] . ' Server geladen.',
                                ['timeout' => 4000, 'urgency' => 'normal'],
                            );
                        }

                        // Danach: pro Server asynchron Docker-Infos und Systemstatus nachladen
                        foreach ($serverListTab->currentServerData as $index => $row) {
                            $ip = $row['ipv4'] ?? '';
                            $serverId = $row['id'] ?? null;

                            // Read saved borgmatic passphrase before async task
                            $savedBorgmaticPassphrase = null;
                            if ($serverId !== null) {
                                $savedBorgmaticPassphrase = $serverListTab->settings->get(
                                    'servers.' . $serverId . '.borgmatic_passphrase',
                                    null
                                );
                            }

                            if (empty($ip) || empty($currentPrivateKeyPath) || !file_exists($currentPrivateKeyPath)) {
                                $serverListTab->currentServerData[$index]['docker_error'] = 'Kein gültiger Private-Key oder IP';
                                $serverListTab->currentServerData[$index]['docker_status'] = 'error';
                                $serverListTab->currentServerData[$index]['docker_running'] = 'error';
                                continue;
                            }

                            $dockerTask = TaskManager::getInstance()->runAsync(function () use (
                                &$ip,
                                &$currentPrivateKeyPath,
                                &$index,
                                &$serverId,
                                &$savedBorgmaticPassphrase,
                            ) {
                                try {
                                    $ssh = new \phpseclib3\Net\SSH2($ip);
                                    $key = \phpseclib3\Crypt\PublicKeyLoader::loadPrivateKey(file_get_contents(
                                        $currentPrivateKeyPath,
                                    ));

                                    if (!$ssh->login('root', $key)) {
                                        return [
                                            'index' => $index,
                                            'docker' => 'fetch usage',
                                            'docker_error' => 'SSH Login fehlgeschlagen',
                                            'docker_status' => 'error',
                                            'ssh_keys' => [],
                                            'borgmatic_passphrase' => null,
                                            'server_id' => $serverId,
                                        ];
                                    }

                                    // Check if reboot is required (Ubuntu)
                                    $rebootOutput = trim($ssh->exec(
                                        '[ -f /var/run/reboot-required ] && echo yes || echo no',
                                    ));
                                    $needsReboot = $rebootOutput === 'yes';

                                    // Check number of available package updates (Ubuntu)
                                    $updatesOutput = trim($ssh->exec(
                                        'apt-get -s upgrade 2>/dev/null | grep -c "^Inst " || echo 0',
                                    ));
                                    $updatesCount = is_numeric($updatesOutput) ? (int) $updatesOutput : 0;

                                    // Read Ubuntu version (PRETTY_NAME from /etc/os-release)
                                    $osOutput = trim($ssh->exec(
                                        'grep "^PRETTY_NAME=" /etc/os-release 2>/dev/null | cut -d= -f2 | tr -d \'"\'',
                                    ));
                                    $osVersion = $osOutput !== '' ? $osOutput : 'unbekannt';

                                    // Read authorized SSH keys
                                    $sshKeysOutput = trim($ssh->exec(
                                        'cat ~/.ssh/authorized_keys 2>/dev/null || echo ""',
                                    ));
                                    $sshKeys = [];
                                    if ($sshKeysOutput !== '') {
                                        $lines = preg_split('/\r\n|\r|\n/', $sshKeysOutput);
                                        foreach ($lines as $line) {
                                            $line = trim($line);
                                            // Skip empty lines and comments
                                            if ($line !== '' && !str_starts_with($line, '#')) {
                                                $sshKeys[] = $line;
                                            }
                                        }
                                    }

                                    // Read borgmatic passphrase (only if not already saved locally)
                                    $borgmaticPassphrase = null;
                                    if ($serverId !== null) {
                                        $logFile = '/tmp/borgmatic_debug.log';
                                        file_put_contents(
                                            $logFile,
                                            '[' . date('Y-m-d H:i:s') . "] Server ID: {$serverId}\n",
                                            FILE_APPEND,
                                        );
                                        file_put_contents(
                                            $logFile,
                                            'Saved passphrase: ' . ($savedBorgmaticPassphrase ?? 'NULL') . "\n",
                                            FILE_APPEND,
                                        );

                                        if ($savedBorgmaticPassphrase === null || $savedBorgmaticPassphrase === '') {
                                            // Read from server
                                            $borgmaticConfigOutput = trim($ssh->exec(
                                                'cat /etc/borgmatic/config.yaml 2>/dev/null || echo ""',
                                            ));

                                            file_put_contents(
                                                $logFile,
                                                'Config length: ' . strlen($borgmaticConfigOutput) . " bytes\n",
                                                FILE_APPEND,
                                            );

                                            if ($borgmaticConfigOutput !== '') {
                                                // Extract passphrase from YAML (with leading whitespace)
                                                if (preg_match(
                                                    '/^\s*encryption_passphrase:\s*["\']([^"\']+)["\']/m',
                                                    $borgmaticConfigOutput,
                                                    $matches,
                                                )) {
                                                    $borgmaticPassphrase = $matches[1];
                                                    file_put_contents(
                                                        $logFile,
                                                        "Found passphrase with quotes: {$borgmaticPassphrase}\n",
                                                        FILE_APPEND,
                                                    );
                                                } elseif (preg_match(
                                                    '/^\s*encryption_passphrase:\s*([^\s]+)/m',
                                                    $borgmaticConfigOutput,
                                                    $matches,
                                                )) {
                                                    $borgmaticPassphrase = trim($matches[1]);
                                                    file_put_contents(
                                                        $logFile,
                                                        "Found passphrase without quotes: {$borgmaticPassphrase}\n",
                                                        FILE_APPEND,
                                                    );
                                                } else {
                                                    file_put_contents($logFile, "No passphrase found!\n", FILE_APPEND);
                                                    file_put_contents(
                                                        $logFile,
                                                        "First 300 chars:\n"
                                                        . substr($borgmaticConfigOutput, 0, 300)
                                                        . "\n",
                                                        FILE_APPEND,
                                                    );
                                                }

                                                // Passphrase will be saved in onComplete handler
                                            } else {
                                                file_put_contents(
                                                    $logFile,
                                                    "Config file empty or not found\n",
                                                    FILE_APPEND,
                                                );
                                            }
                                        } else {
                                            $borgmaticPassphrase = $savedBorgmaticPassphrase;
                                            file_put_contents(
                                                $logFile,
                                                "Using saved passphrase: {$borgmaticPassphrase}\n",
                                                FILE_APPEND,
                                            );
                                        }
                                        file_put_contents($logFile, "---\n", FILE_APPEND);
                                    }

                                    // Last backup from borgmatic
                                    $lastBackup = 'unbekannt';
                                    $borgmaticOutput = trim($ssh->exec(
                                        'borgmatic list --last 1 --json 2>/dev/null || echo ""',
                                    ));
                                    if ($borgmaticOutput !== '') {
                                        $borgmaticData = json_decode($borgmaticOutput, true);
                                        if (
                                            json_last_error() === JSON_ERROR_NONE
                                            && is_array($borgmaticData)
                                            && !empty($borgmaticData)
                                        ) {
                                            // borgmatic list --json gibt ein Array von Repositories zurück
                                            $firstRepo = reset($borgmaticData);
                                            if (
                                                is_array($firstRepo)
                                                && isset($firstRepo['archives'])
                                                && is_array($firstRepo['archives'])
                                                && !empty($firstRepo['archives'])
                                            ) {
                                                $lastArchive = reset($firstRepo['archives']);
                                                if (
                                                    is_array($lastArchive)
                                                    && isset($lastArchive['time'])
                                                    && is_string($lastArchive['time'])
                                                ) {
                                                    try {
                                                        $backupTime = new \DateTime($lastArchive['time']);
                                                        $lastBackup = $backupTime->format('d.m.Y H:i');
                                                    } catch (\Exception $e) {
                                                        $lastBackup = $lastArchive['time'];
                                                    }
                                                }
                                            }
                                        }
                                    }

                                    // Disk usage for / and /data
                                    $rootUsage = 'unbekannt';
                                    $dfRoot = trim($ssh->exec('df -P / 2>/dev/null'));
                                    if ($dfRoot !== '') {
                                        $lines = preg_split('/\r\n|\r|\n/', $dfRoot);
                                        if (count($lines) >= 2) {
                                            $parts = preg_split('/\s+/', trim($lines[1]));
                                            if (isset($parts[4]) && $parts[4] !== '') {
                                                $rootUsage = $parts[4];
                                            }
                                        }
                                    }

                                    $dataUsage = 'unbekannt';
                                    $dfData = trim($ssh->exec('df -P /data 2>/dev/null'));
                                    if ($dfData !== '') {
                                        $lines = preg_split('/\r\n|\r|\n/', $dfData);
                                        if (count($lines) >= 2) {
                                            $parts = preg_split('/\s+/', trim($lines[1]));
                                            if (isset($parts[4]) && $parts[4] !== '') {
                                                $dataUsage = $parts[4];
                                            }
                                        }
                                    }

                                    // Docker status for main application container
                                    $runningOutput = trim($ssh->exec(
                                        "docker ps --filter status=running --format '{{.ID}}' | wc -l",
                                    ));
                                    $runningCount = is_numeric($runningOutput) ? (int) $runningOutput : null;

                                    $output = $ssh->exec('docker inspect psc-web-1');
                                    if (empty($output)) {
                                        return [
                                            'index' => $index,
                                            'docker' => null,
                                            'docker_error' => 'Leere Docker-Antwort',
                                            'docker_status' => 'error',
                                            'docker_running' => $runningCount,
                                            'needs_reboot' => $needsReboot,
                                            'updates' => $updatesCount,
                                            'os_version' => $osVersion,
                                            'root' => $rootUsage,
                                            'data' => $dataUsage,
                                            'last_backup' => $lastBackup,
                                            'ssh_keys' => $sshKeys,
                                            'borgmatic_passphrase' => $borgmaticPassphrase,
                                            'server_id' => $serverId,
                                        ];
                                    }

                                    $json = json_decode($output, true);
                                    if (json_last_error() !== JSON_ERROR_NONE) {
                                        return [
                                            'index' => $index,
                                            'docker' => null,
                                            'docker_error' => 'Ungültige Docker-JSON-Antwort',
                                            'docker_status' => 'error',
                                            'docker_running' => $runningCount,
                                            'needs_reboot' => $needsReboot,
                                            'updates' => $updatesCount,
                                            'os_version' => $osVersion,
                                            'root' => $rootUsage,
                                            'data' => $dataUsage,
                                            'last_backup' => $lastBackup,
                                            'ssh_keys' => $sshKeys,
                                            'borgmatic_passphrase' => $borgmaticPassphrase,
                                            'server_id' => $serverId,
                                        ];
                                    }

                                    $domains = [];
                                    if (isset($json[0]['Config']['Env']) && is_array($json[0]['Config']['Env'])) {
                                        $hosts = array_filter($json[0]['Config']['Env'], static function ($item) {
                                            return is_string($item) && str_starts_with($item, 'LETSENCRYPT_HOST');
                                        });
                                        if (!empty($hosts)) {
                                            $hostEntry = array_first($hosts);
                                            $hostString = substr((string) $hostEntry, strlen('LETSENCRYPT_HOST='));
                                            $domains = array_values(array_filter(
                                                array_map('trim', explode(',', $hostString)),
                                                static fn($d) => $d !== '',
                                            ));
                                        }
                                    }

                                    $release = 'unbekannt';
                                    if (!empty($domains)) {
                                        $releaseDomain = $domains[0];
                                        $releaseDomain = trim($releaseDomain);
                                        if ($releaseDomain !== '') {
                                            $url = $releaseDomain;
                                            if (
                                                !str_starts_with($url, 'http://') && !str_starts_with($url, 'https://')
                                            ) {
                                                $url = 'https://' . $url;
                                            }
                                            $url = rtrim($url, '/') . '/apps/api/system/version';

                                            try {
                                                $context = stream_context_create([
                                                    'http' => [
                                                        'method' => 'GET',
                                                        'timeout' => 5,
                                                    ],
                                                ]);

                                                $response = file_get_contents($url, false, $context);
                                                if ($response !== false) {
                                                    $data = json_decode($response, true);
                                                    if (json_last_error() === JSON_ERROR_NONE && is_array($data)) {
                                                        $releaseValue = null;
                                                        if (isset($data['version']) && is_string($data['version'])) {
                                                            $releaseValue = trim($data['version']);
                                                        } elseif (
                                                            isset($data['release']) && is_string($data['release'])
                                                        ) {
                                                            $releaseValue = trim($data['release']);
                                                        }

                                                        $dateValue = null;
                                                        if (isset($data['datum']) && is_string($data['datum'])) {
                                                            $dateValue = trim($data['datum']);
                                                        }

                                                        if (
                                                            $releaseValue !== null
                                                            && $dateValue !== null
                                                            && $dateValue !== ''
                                                        ) {
                                                            $release = $releaseValue . ' (' . $dateValue . ')';
                                                        } elseif ($releaseValue !== null) {
                                                            $release = $releaseValue;
                                                        } elseif ($dateValue !== null && $dateValue !== '') {
                                                            $release = $dateValue;
                                                        } else {
                                                            $release = 'unbekannt';
                                                        }
                                                    } else {
                                                        $release = 'Ungültig';
                                                    }
                                                } else {
                                                    $release = 'Fehler';
                                                }
                                            } catch (\Throwable) {
                                                $release = 'Fehler';
                                            }
                                        }
                                    }

                                    return [
                                        'index' => $index,
                                        'docker' => $json,
                                        'docker_error' => null,
                                        'docker_status' => 'ok',
                                        'docker_running' => $runningCount,
                                        'needs_reboot' => $needsReboot,
                                        'updates' => $updatesCount,
                                        'os_version' => $osVersion,
                                        'root' => $rootUsage,
                                        'data' => $dataUsage,
                                        'domains' => $domains,
                                        'release' => $release,
                                        'last_backup' => $lastBackup,
                                        'ssh_keys' => $sshKeys,
                                        'borgmatic_passphrase' => $borgmaticPassphrase,
                                        'server_id' => $serverId,
                                    ];
                                } catch (\Throwable $e) {
                                    return [
                                        'index' => $index,
                                        'docker' => null,
                                        'docker_error' => 'SSH-Fehler: ' . $e->getMessage(),
                                        'docker_status' => 'error',
                                        'docker_running' => null,
                                        'needs_reboot' => null,
                                        'updates' => null,
                                        'os_version' => null,
                                        'root' => 'unbekannt',
                                        'data' => 'unbekannt',
                                        'last_backup' => 'unbekannt',
                                        'ssh_keys' => [],
                                        'borgmatic_passphrase' => null,
                                        'server_id' => $serverId,
                                    ];
                                }
                            });

                            $dockerTask->onComplete(function ($dockerResult) use (&$serverListTab) {
                                if (!is_array($dockerResult) || !isset($dockerResult['index'])) {
                                    return;
                                }

                                $i = $dockerResult['index'];
                                if (!isset($serverListTab->currentServerData[$i])) {
                                    return;
                                }

                                if (array_key_exists('docker', $dockerResult)) {
                                    $serverListTab->currentServerData[$i]['docker'] = $dockerResult['docker'];
                                    $searchTerm = strtolower(trim($serverListTab->searchInput->getValue()));
                                    if (empty($searchTerm)) {
                                        $serverListTab->table->updateData($serverListTab->currentServerData);
                                    } else {
                                        $filteredData = array_filter(
                                            $serverListTab->currentServerData,
                                            function ($row) use ($searchTerm) {
                                                if (str_contains(strtolower($row['name']), $searchTerm)) {
                                                    return true;
                                                }
                                                $domains = $row['domains'] ?? [];
                                                if (
                                                    is_array($domains)
                                                    && count(array_filter($domains, function ($item) use ($searchTerm) {
                                                        return str_contains(strtolower($item), $searchTerm);
                                                    }))
                                                ) {
                                                    return true;
                                                }
                                                $sshKeys = $row['ssh_keys'] ?? [];
                                                if (
                                                    is_array($sshKeys)
                                                    && count(array_filter($sshKeys, function ($item) use ($searchTerm) {
                                                        return str_contains(strtolower($item), $searchTerm);
                                                    }))
                                                ) {
                                                    return true;
                                                }
                                                return false;
                                            },
                                        );
                                        $serverListTab->table->updateData(array_values($filteredData));
                                    }
                                }

                                if (array_key_exists('domains', $dockerResult)) {
                                    $domains = $dockerResult['domains'];
                                    if (!is_array($domains)) {
                                        $domains = [];
                                    }
                                    $serverListTab->currentServerData[$i]['domains'] = $domains;
                                }

                                // Map system status into human-readable table fields
                                if (array_key_exists('needs_reboot', $dockerResult)) {
                                    $needsReboot = $dockerResult['needs_reboot'];
                                    if ($needsReboot === null) {
                                        $serverListTab->currentServerData[$i]['needs_reboot'] = 'unbekannt';
                                    } else {
                                        $serverListTab->currentServerData[$i]['needs_reboot'] = $needsReboot
                                            ? 'ja'
                                            : 'nein';
                                    }
                                }

                                if (array_key_exists('updates', $dockerResult)) {
                                    $updates = (int) ($dockerResult['updates'] ?? 0);
                                    $serverListTab->currentServerData[$i]['updates_available'] = $updates > 0
                                        ? 'ja (' . $updates . ')'
                                        : 'nein';
                                }

                                if (array_key_exists('os_version', $dockerResult)) {
                                    $osVersion = $dockerResult['os_version'];
                                    $serverListTab->currentServerData[$i]['os_version'] = $osVersion !== null
                                        ? $osVersion
                                        : 'unbekannt';
                                }

                                if (array_key_exists('root', $dockerResult)) {
                                    $rootUsage = $dockerResult['root'];
                                    $serverListTab->currentServerData[$i]['root'] = $rootUsage !== null
                                        ? $rootUsage
                                        : 'unbekannt';
                                }

                                if (array_key_exists('data', $dockerResult)) {
                                    $dataUsage = $dockerResult['data'];
                                    $serverListTab->currentServerData[$i]['data'] = $dataUsage !== null
                                        ? $dataUsage
                                        : 'unbekannt';
                                }

                                if (array_key_exists('release', $dockerResult)) {
                                    $release = $dockerResult['release'];
                                    $serverListTab->currentServerData[$i]['release'] = $release !== null
                                        ? $release
                                        : 'unbekannt';
                                }

                                if (array_key_exists('docker_error', $dockerResult)) {
                                    $serverListTab->currentServerData[$i]['docker_error'] =
                                        $dockerResult['docker_error'];
                                }

                                if (array_key_exists('docker_status', $dockerResult)) {
                                    $serverListTab->currentServerData[$i]['docker_status'] =
                                        $dockerResult['docker_status'];
                                }

                                if (array_key_exists('docker_running', $dockerResult)) {
                                    $serverListTab->currentServerData[$i]['docker_running'] =
                                        $dockerResult['docker_running'] !== null
                                            ? $dockerResult['docker_running']
                                            : 'unbekannt';
                                }

                                if (array_key_exists('last_backup', $dockerResult)) {
                                    $lastBackup = $dockerResult['last_backup'];
                                    $serverListTab->currentServerData[$i]['last_backup'] = $lastBackup !== null
                                        ? $lastBackup
                                        : 'unbekannt';
                                }

                                if (array_key_exists('ssh_keys', $dockerResult)) {
                                    $sshKeys = $dockerResult['ssh_keys'];
                                    if (!is_array($sshKeys)) {
                                        $sshKeys = [];
                                    }
                                    $serverListTab->currentServerData[$i]['ssh_keys'] = $sshKeys;
                                }

                                // Save borgmatic passphrase if found and new
                                if (array_key_exists('borgmatic_passphrase', $dockerResult)
                                    && array_key_exists('server_id', $dockerResult)
                                    && $dockerResult['borgmatic_passphrase'] !== null
                                    && $dockerResult['borgmatic_passphrase'] !== ''
                                    && $dockerResult['server_id'] !== null) {
                                    $serverId = $dockerResult['server_id'];
                                    $passphrase = $dockerResult['borgmatic_passphrase'];
                                    $serverListTab->settings->set(
                                        'servers.' . $serverId . '.borgmatic_passphrase',
                                        $passphrase
                                    );
                                    $serverListTab->settings->save();
                                }
                            });

                            $dockerTask->onError(function ($error) use (&$serverListTab, $index) {
                                $errorMsg = is_object($error) && method_exists($error, 'getMessage')
                                    ? $error->getMessage()
                                    : (string) $error;
                                if (isset($serverListTab->currentServerData[$index])) {
                                    $serverListTab->currentServerData[$index]['docker_error'] =
                                        'Async Fehler: ' . $errorMsg;
                                    $serverListTab->currentServerData[$index]['docker_running'] = 'error';
                                }
                            });
                        }
                    }
                }

                $serverListTab->loadingIndicator->setLoading(false);
            });

            $task->onError(function ($error) use (&$serverListTab) {
                $errorMsg = is_object($error) && method_exists($error, 'getMessage')
                    ? $error->getMessage()
                    : (string) $error;
                $serverListTab->statusLabel->setText('Async Fehler: ' . $errorMsg);
                echo "Async error: {$errorMsg}\n";

                $serverListTab->loadingIndicator->setLoading(false);
            });
        });

        // Refresh selected servers only
        $refreshSelectedButton->setOnClick(function () use (&$currentApiKey, $serverListTab, &$currentPrivateKeyPath) {
            $selected = [];
            foreach ($serverListTab->currentServerData as $index => $row) {
                if (!empty($row['selected'])) {
                    $selected[] = ['index' => $index, 'row' => $row];
                }
            }

            if (empty($selected)) {
                $serverListTab->statusLabel->setText('Keine Server ausgewählt für Aktualisierung');
                return;
            }

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

            $serverListTab->loadingIndicator->setLoading(true);
            $serverListTab->statusLabel->setText('Aktualisiere ' . count($selected) . ' ausgewählte Server...');

            foreach ($selected as $item) {
                $index = $item['index'];
                $row = $item['row'];
                $ip = $row['ipv4'] ?? '';
                $serverId = $row['id'] ?? null;

                // Read saved borgmatic passphrase before async task
                $savedBorgmaticPassphrase = null;
                if ($serverId !== null) {
                    $savedBorgmaticPassphrase = $serverListTab->settings->get(
                        'servers.' . $serverId . '.borgmatic_passphrase',
                        null
                    );
                }

                if (empty($ip)) {
                    continue;
                }

                // Mark as pending
                $serverListTab->currentServerData[$index]['docker_status'] = 'pending';
                $serverListTab->currentServerData[$index]['docker_running'] = 'pending';

                $dockerTask = TaskManager::getInstance()->runAsync(function () use (
                    &$ip,
                    &$currentPrivateKeyPath,
                    &$index,
                    &$serverId,
                    &$savedBorgmaticPassphrase,
                ) {
                    try {
                        $ssh = new \phpseclib3\Net\SSH2($ip);
                        $key = \phpseclib3\Crypt\PublicKeyLoader::loadPrivateKey(file_get_contents(
                            $currentPrivateKeyPath,
                        ));

                        if (!$ssh->login('root', $key)) {
                            return [
                                'index' => $index,
                                'docker' => 'fetch usage',
                                'docker_error' => 'SSH Login fehlgeschlagen',
                                'docker_status' => 'error',
                                'ssh_keys' => [],
                                'borgmatic_passphrase' => null,
                                'server_id' => $serverId,
                            ];
                        }

                        // Check if reboot is required (Ubuntu)
                        $rebootOutput = trim($ssh->exec('[ -f /var/run/reboot-required ] && echo yes || echo no'));
                        $needsReboot = $rebootOutput === 'yes';

                        // Check number of available package updates (Ubuntu)
                        $updatesOutput = trim($ssh->exec(
                            'apt-get -s upgrade 2>/dev/null | grep -c "^Inst " || echo 0',
                        ));
                        $updatesCount = is_numeric($updatesOutput) ? (int) $updatesOutput : 0;

                        // Read Ubuntu version (PRETTY_NAME from /etc/os-release)
                        $osOutput = trim($ssh->exec(
                            'grep "^PRETTY_NAME=" /etc/os-release 2>/dev/null | cut -d= -f2 | tr -d \'"\'',
                        ));
                        $osVersion = $osOutput !== '' ? $osOutput : 'unbekannt';

                        // Read authorized SSH keys
                        $sshKeysOutput = trim($ssh->exec('cat ~/.ssh/authorized_keys 2>/dev/null || echo ""'));
                        $sshKeys = [];
                        if ($sshKeysOutput !== '') {
                            $lines = preg_split('/\r\n|\r|\n/', $sshKeysOutput);
                            foreach ($lines as $line) {
                                $line = trim($line);
                                // Skip empty lines and comments
                                if ($line !== '' && !str_starts_with($line, '#')) {
                                    $sshKeys[] = $line;
                                }
                            }
                        }

                        // Read borgmatic passphrase (only if not already saved locally)
                        $borgmaticPassphrase = null;
                        if ($serverId !== null) {
                            $logFile = '/tmp/borgmatic_debug.log';
                            file_put_contents(
                                $logFile,
                                '[' . date('Y-m-d H:i:s') . "] Server ID: {$serverId}\n",
                                FILE_APPEND,
                            );
                            file_put_contents(
                                $logFile,
                                'Saved passphrase: ' . ($savedBorgmaticPassphrase ?? 'NULL') . "\n",
                                FILE_APPEND,
                            );

                            if ($savedBorgmaticPassphrase === null || $savedBorgmaticPassphrase === '') {
                                // Read from server
                                $borgmaticConfigOutput = trim($ssh->exec(
                                    'cat /etc/borgmatic/config.yaml 2>/dev/null || echo ""',
                                ));

                                file_put_contents(
                                    $logFile,
                                    'Config length: ' . strlen($borgmaticConfigOutput) . " bytes\n",
                                    FILE_APPEND,
                                );

                                if ($borgmaticConfigOutput !== '') {
                                    // Extract passphrase from YAML (with leading whitespace)
                                    if (preg_match(
                                        '/^\s*encryption_passphrase:\s*["\']([^"\']+)["\']/m',
                                        $borgmaticConfigOutput,
                                        $matches,
                                    )) {
                                        $borgmaticPassphrase = $matches[1];
                                        file_put_contents(
                                            $logFile,
                                            "Found passphrase with quotes: {$borgmaticPassphrase}\n",
                                            FILE_APPEND,
                                        );
                                    } elseif (preg_match(
                                        '/^\s*encryption_passphrase:\s*([^\s]+)/m',
                                        $borgmaticConfigOutput,
                                        $matches,
                                    )) {
                                        $borgmaticPassphrase = trim($matches[1]);
                                        file_put_contents(
                                            $logFile,
                                            "Found passphrase without quotes: {$borgmaticPassphrase}\n",
                                            FILE_APPEND,
                                        );
                                    } else {
                                        file_put_contents($logFile, "No passphrase found!\n", FILE_APPEND);
                                        file_put_contents(
                                            $logFile,
                                            "First 300 chars:\n" . substr($borgmaticConfigOutput, 0, 300) . "\n",
                                            FILE_APPEND,
                                        );
                                    }

                                    // Passphrase will be saved in onComplete handler
                                } else {
                                    file_put_contents($logFile, "Config file empty or not found\n", FILE_APPEND);
                                }
                            } else {
                                $borgmaticPassphrase = $savedBorgmaticPassphrase;
                                file_put_contents(
                                    $logFile,
                                    "Using saved passphrase: {$borgmaticPassphrase}\n",
                                    FILE_APPEND,
                                );
                            }
                            file_put_contents($logFile, "---\n", FILE_APPEND);
                        }

                        // Last backup from borgmatic
                        $lastBackup = 'unbekannt';
                        $borgmaticOutput = trim($ssh->exec('borgmatic list --last 1 --json 2>/dev/null || echo ""'));
                        if ($borgmaticOutput !== '') {
                            $borgmaticData = json_decode($borgmaticOutput, true);
                            if (
                                json_last_error() === JSON_ERROR_NONE
                                && is_array($borgmaticData)
                                && !empty($borgmaticData)
                            ) {
                                // borgmatic list --json gibt ein Array von Repositories zurück
                                $firstRepo = reset($borgmaticData);
                                if (
                                    is_array($firstRepo)
                                    && isset($firstRepo['archives'])
                                    && is_array($firstRepo['archives'])
                                    && !empty($firstRepo['archives'])
                                ) {
                                    $lastArchive = reset($firstRepo['archives']);
                                    if (
                                        is_array($lastArchive)
                                        && isset($lastArchive['time'])
                                        && is_string($lastArchive['time'])
                                    ) {
                                        try {
                                            $backupTime = new \DateTime($lastArchive['time']);
                                            $lastBackup = $backupTime->format('d.m.Y H:i');
                                        } catch (\Exception $e) {
                                            $lastBackup = $lastArchive['time'];
                                        }
                                    }
                                }
                            }
                        }

                        // Disk usage for / and /data
                        $rootUsage = 'unbekannt';
                        $dfRoot = trim($ssh->exec('df -P / 2>/dev/null'));
                        if ($dfRoot !== '') {
                            $lines = preg_split('/\r\n|\r|\n/', $dfRoot);
                            if (count($lines) >= 2) {
                                $parts = preg_split('/\s+/', trim($lines[1]));
                                if (isset($parts[4]) && $parts[4] !== '') {
                                    $rootUsage = $parts[4];
                                }
                            }
                        }

                        $dataUsage = 'unbekannt';
                        $dfData = trim($ssh->exec('df -P /data 2>/dev/null'));
                        if ($dfData !== '') {
                            $lines = preg_split('/\r\n|\r|\n/', $dfData);
                            if (count($lines) >= 2) {
                                $parts = preg_split('/\s+/', trim($lines[1]));
                                if (isset($parts[4]) && $parts[4] !== '') {
                                    $dataUsage = $parts[4];
                                }
                            }
                        }

                        // Docker status for main application container
                        $runningOutput = trim($ssh->exec(
                            "docker ps --filter status=running --format '{{.ID}}' | wc -l",
                        ));
                        $runningCount = is_numeric($runningOutput) ? (int) $runningOutput : null;

                        $output = $ssh->exec('docker inspect psc-web-1');
                        if (empty($output)) {
                            return [
                                'index' => $index,
                                'docker' => null,
                                'docker_error' => 'Leere Docker-Antwort',
                                'docker_status' => 'error',
                                'docker_running' => $runningCount,
                                'needs_reboot' => $needsReboot,
                                'updates' => $updatesCount,
                                'os_version' => $osVersion,
                                'root' => $rootUsage,
                                'data' => $dataUsage,
                                'last_backup' => $lastBackup,
                                'ssh_keys' => $sshKeys,
                                'borgmatic_passphrase' => $borgmaticPassphrase,
                                'server_id' => $serverId,
                            ];
                        }

                        $json = json_decode($output, true);
                        if (json_last_error() !== JSON_ERROR_NONE) {
                            return [
                                'index' => $index,
                                'docker' => null,
                                'docker_error' => 'Ungültige Docker-JSON-Antwort',
                                'docker_status' => 'error',
                                'docker_running' => $runningCount,
                                'needs_reboot' => $needsReboot,
                                'updates' => $updatesCount,
                                'os_version' => $osVersion,
                                'root' => $rootUsage,
                                'data' => $dataUsage,
                                'last_backup' => $lastBackup,
                                'ssh_keys' => $sshKeys,
                                'borgmatic_passphrase' => $borgmaticPassphrase,
                                'server_id' => $serverId,
                            ];
                        }

                        $domains = [];
                        if (isset($json[0]['Config']['Env']) && is_array($json[0]['Config']['Env'])) {
                            $hosts = array_filter($json[0]['Config']['Env'], static function ($item) {
                                return is_string($item) && str_starts_with($item, 'LETSENCRYPT_HOST');
                            });
                            if (!empty($hosts)) {
                                $hostEntry = array_first($hosts);
                                $hostString = substr((string) $hostEntry, strlen('LETSENCRYPT_HOST='));
                                $domains = array_values(array_filter(
                                    array_map('trim', explode(',', $hostString)),
                                    static fn($d) => $d !== '',
                                ));
                            }
                        }

                        $release = 'unbekannt';
                        if (!empty($domains)) {
                            $releaseDomain = $domains[0];
                            $releaseDomain = trim($releaseDomain);
                            if ($releaseDomain !== '') {
                                $url = $releaseDomain;
                                if (!str_starts_with($url, 'http://') && !str_starts_with($url, 'https://')) {
                                    $url = 'https://' . $url;
                                }
                                $url = rtrim($url, '/') . '/apps/api/system/version';

                                try {
                                    $context = stream_context_create([
                                        'http' => [
                                            'method' => 'GET',
                                            'timeout' => 5,
                                        ],
                                    ]);

                                    $response = file_get_contents($url, false, $context);
                                    if ($response !== false) {
                                        $data = json_decode($response, true);
                                        if (json_last_error() === JSON_ERROR_NONE && is_array($data)) {
                                            $releaseValue = null;
                                            if (isset($data['version']) && is_string($data['version'])) {
                                                $releaseValue = trim($data['version']);
                                            } elseif (isset($data['release']) && is_string($data['release'])) {
                                                $releaseValue = trim($data['release']);
                                            }

                                            $dateValue = null;
                                            if (isset($data['datum']) && is_string($data['datum'])) {
                                                $dateValue = trim($data['datum']);
                                            }

                                            if ($releaseValue !== null && $dateValue !== null && $dateValue !== '') {
                                                $release = $releaseValue . ' (' . $dateValue . ')';
                                            } elseif ($releaseValue !== null) {
                                                $release = $releaseValue;
                                            } elseif ($dateValue !== null && $dateValue !== '') {
                                                $release = $dateValue;
                                            } else {
                                                $release = 'unbekannt';
                                            }
                                        } else {
                                            $release = 'Ungültig';
                                        }
                                    } else {
                                        $release = 'Fehler';
                                    }
                                } catch (\Throwable) {
                                    $release = 'Fehler';
                                }
                            }
                        }

                        return [
                            'index' => $index,
                            'docker' => $json,
                            'docker_error' => null,
                            'docker_status' => 'ok',
                            'docker_running' => $runningCount,
                            'needs_reboot' => $needsReboot,
                            'updates' => $updatesCount,
                            'os_version' => $osVersion,
                            'root' => $rootUsage,
                            'data' => $dataUsage,
                            'domains' => $domains,
                            'release' => $release,
                            'last_backup' => $lastBackup,
                            'ssh_keys' => $sshKeys,
                            'borgmatic_passphrase' => $borgmaticPassphrase,
                            'server_id' => $serverId,
                        ];
                    } catch (\Throwable $e) {
                        return [
                            'index' => $index,
                            'docker' => null,
                            'docker_error' => 'SSH-Fehler: ' . $e->getMessage(),
                            'docker_status' => 'error',
                            'docker_running' => null,
                            'needs_reboot' => null,
                            'updates' => null,
                            'os_version' => null,
                            'root' => 'unbekannt',
                            'data' => 'unbekannt',
                            'last_backup' => 'unbekannt',
                            'ssh_keys' => [],
                            'borgmatic_passphrase' => null,
                            'server_id' => $serverId,
                        ];
                    }
                });

                $dockerTask->onComplete(function ($dockerResult) use (&$serverListTab, &$selected) {
                    if (!is_array($dockerResult) || !isset($dockerResult['index'])) {
                        return;
                    }

                    $i = $dockerResult['index'];
                    if (!isset($serverListTab->currentServerData[$i])) {
                        return;
                    }

                    if (array_key_exists('docker', $dockerResult)) {
                        $serverListTab->currentServerData[$i]['docker'] = $dockerResult['docker'];
                    }

                    if (array_key_exists('domains', $dockerResult)) {
                        $domains = $dockerResult['domains'];
                        if (!is_array($domains)) {
                            $domains = [];
                        }
                        $serverListTab->currentServerData[$i]['domains'] = $domains;
                    }

                    // Map system status into human-readable table fields
                    if (array_key_exists('needs_reboot', $dockerResult)) {
                        $needsReboot = $dockerResult['needs_reboot'];
                        if ($needsReboot === null) {
                            $serverListTab->currentServerData[$i]['needs_reboot'] = 'unbekannt';
                        } else {
                            $serverListTab->currentServerData[$i]['needs_reboot'] = $needsReboot ? 'ja' : 'nein';
                        }
                    }

                    if (array_key_exists('updates', $dockerResult)) {
                        $updates = (int) ($dockerResult['updates'] ?? 0);
                        $serverListTab->currentServerData[$i]['updates_available'] = $updates > 0
                            ? 'ja (' . $updates . ')'
                            : 'nein';
                    }

                    if (array_key_exists('os_version', $dockerResult)) {
                        $osVersion = $dockerResult['os_version'];
                        $serverListTab->currentServerData[$i]['os_version'] = $osVersion !== null
                            ? $osVersion
                            : 'unbekannt';
                    }

                    if (array_key_exists('root', $dockerResult)) {
                        $rootUsage = $dockerResult['root'];
                        $serverListTab->currentServerData[$i]['root'] = $rootUsage !== null ? $rootUsage : 'unbekannt';
                    }

                    if (array_key_exists('data', $dockerResult)) {
                        $dataUsage = $dockerResult['data'];
                        $serverListTab->currentServerData[$i]['data'] = $dataUsage !== null ? $dataUsage : 'unbekannt';
                    }

                    if (array_key_exists('release', $dockerResult)) {
                        $release = $dockerResult['release'];
                        $serverListTab->currentServerData[$i]['release'] = $release !== null ? $release : 'unbekannt';
                    }

                    if (array_key_exists('docker_error', $dockerResult)) {
                        $serverListTab->currentServerData[$i]['docker_error'] = $dockerResult['docker_error'];
                    }

                    if (array_key_exists('docker_status', $dockerResult)) {
                        $serverListTab->currentServerData[$i]['docker_status'] = $dockerResult['docker_status'];
                    }

                    if (array_key_exists('docker_running', $dockerResult)) {
                        $serverListTab->currentServerData[$i]['docker_running'] = $dockerResult['docker_running']
                        !== null
                            ? $dockerResult['docker_running']
                            : 'unbekannt';
                    }

                    if (array_key_exists('last_backup', $dockerResult)) {
                        $lastBackup = $dockerResult['last_backup'];
                        $serverListTab->currentServerData[$i]['last_backup'] = $lastBackup !== null
                            ? $lastBackup
                            : 'unbekannt';
                    }

                    if (array_key_exists('ssh_keys', $dockerResult)) {
                        $sshKeys = $dockerResult['ssh_keys'];
                        if (!is_array($sshKeys)) {
                            $sshKeys = [];
                        }
                        $serverListTab->currentServerData[$i]['ssh_keys'] = $sshKeys;
                    }

                    // Save borgmatic passphrase if found and new
                    if (array_key_exists('borgmatic_passphrase', $dockerResult)
                        && array_key_exists('server_id', $dockerResult)
                        && $dockerResult['borgmatic_passphrase'] !== null
                        && $dockerResult['borgmatic_passphrase'] !== ''
                        && $dockerResult['server_id'] !== null) {
                        $serverId = $dockerResult['server_id'];
                        $passphrase = $dockerResult['borgmatic_passphrase'];
                        $serverListTab->settings->set(
                            'servers.' . $serverId . '.borgmatic_passphrase',
                            $passphrase
                        );
                        $serverListTab->settings->save();
                    }

                    // Update table display
                    $searchTerm = strtolower(trim($serverListTab->searchInput->getValue()));
                    if (empty($searchTerm)) {
                        $serverListTab->table->updateData($serverListTab->currentServerData);
                    } else {
                        $filteredData = array_filter($serverListTab->currentServerData, function ($row) use (
                            $searchTerm,
                        ) {
                            if (str_contains(strtolower($row['name']), $searchTerm)) {
                                return true;
                            }
                            $domains = $row['domains'] ?? [];
                            if (
                                is_array($domains)
                                && count(array_filter($domains, function ($item) use ($searchTerm) {
                                    return str_contains(strtolower($item), $searchTerm);
                                }))
                            ) {
                                return true;
                            }
                            $sshKeys = $row['ssh_keys'] ?? [];
                            if (
                                is_array($sshKeys)
                                && count(array_filter($sshKeys, function ($item) use ($searchTerm) {
                                    return str_contains(strtolower($item), $searchTerm);
                                }))
                            ) {
                                return true;
                            }
                            return false;
                        });
                        $serverListTab->table->updateData(array_values($filteredData));
                    }

                    // Check if all selected servers are done
                    $allDone = true;
                    foreach ($selected as $item) {
                        $idx = $item['index'];
                        $status = $serverListTab->currentServerData[$idx]['docker_status'] ?? 'pending';
                        if ($status === 'pending') {
                            $allDone = false;
                            break;
                        }
                    }

                    if ($allDone) {
                        $serverListTab->loadingIndicator->setLoading(false);
                        $serverListTab->statusLabel->setText(
                            'Aktualisierung abgeschlossen für ' . count($selected) . ' Server',
                        );
                        if (function_exists('desktop_notify')) {
                            desktop_notify(
                                'Server aktualisiert',
                                'Die ausgewählten Server wurden erfolgreich aktualisiert.',
                                ['timeout' => 4000, 'urgency' => 'normal'],
                            );
                        }
                    }
                });

                $dockerTask->onError(function ($error) use (&$serverListTab, $index) {
                    $errorMsg = is_object($error) && method_exists($error, 'getMessage')
                        ? $error->getMessage()
                        : (string) $error;
                    if (isset($serverListTab->currentServerData[$index])) {
                        $serverListTab->currentServerData[$index]['docker_error'] = 'Async Fehler: ' . $errorMsg;
                        $serverListTab->currentServerData[$index]['docker_running'] = 'error';
                        $serverListTab->currentServerData[$index]['docker_status'] = 'error';
                    }
                });
            }

            // Update table to show pending status
            $serverListTab->table->updateData($serverListTab->currentServerData);
        });

        // Reboot selected servers
        $rebootButton->setOnClick(function () use (&$currentPrivateKeyPath, $serverListTab) {
            $selected = [];
            foreach ($serverListTab->currentServerData as $index => $row) {
                if (!empty($row['selected'])) {
                    $selected[] = ['index' => $index, 'row' => $row];
                }
            }

            if (empty($selected)) {
                $serverListTab->statusLabel->setText('Keine Server ausgewählt für Reboot');
                return;
            }

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

            foreach ($selected as $item) {
                $row = $item['row'];
                $ip = $row['ipv4'] ?? '';
                $name = $row['name'] ?? $ip;
                $index = $item['index'];

                if (empty($ip)) {
                    continue;
                }

                $task = TaskManager::getInstance()->runAsync(function () use ($ip, $currentPrivateKeyPath, $index) {
                    try {
                        $ssh = new \phpseclib3\Net\SSH2($ip);
                        $key = \phpseclib3\Crypt\PublicKeyLoader::loadPrivateKey(file_get_contents(
                            $currentPrivateKeyPath,
                        ));

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

                        $ssh->exec('reboot');

                        return [
                            'index' => $index,
                            'success' => true,
                        ];
                    } catch (\Throwable $e) {
                        return [
                            'index' => $index,
                            'success' => false,
                            'error' => 'SSH-Fehler: ' . $e->getMessage(),
                        ];
                    }
                });

                $task->onComplete(function ($result) use (&$serverListTab, $name) {
                    if (!is_array($result) || !array_key_exists('success', $result)) {
                        return;
                    }

                    if ($result['success']) {
                        $serverListTab->statusLabel->setText('Reboot ausgelöst für ' . $name);
                        if (function_exists('desktop_notify')) {
                            desktop_notify('Reboot gestartet', 'Reboot ausgelöst für ' . $name, [
                                'timeout' => 4000,
                                'urgency' => 'normal',
                            ]);
                        }
                    } elseif (isset($result['error'])) {
                        $serverListTab->statusLabel->setText('Reboot Fehler bei ' . $name . ': ' . $result['error']);
                        if (function_exists('desktop_notify')) {
                            desktop_notify('Reboot fehlgeschlagen', 'Fehler bei ' . $name . ': ' . $result['error'], [
                                'timeout' => 6000,
                                'urgency' => 'critical',
                            ]);
                        }
                    }
                });
            }
        });

        // Update selected servers
        $updateButton->setOnClick(function () use (&$currentPrivateKeyPath, $serverListTab) {
            $selected = [];
            foreach ($serverListTab->currentServerData as $index => $row) {
                if (!empty($row['selected'])) {
                    $selected[] = ['index' => $index, 'row' => $row];
                }
            }

            if (empty($selected)) {
                $serverListTab->statusLabel->setText('Keine Server ausgewählt für Updates');
                return;
            }

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

            foreach ($selected as $item) {
                $row = $item['row'];
                $ip = $row['ipv4'] ?? '';
                $name = $row['name'] ?? $ip;
                $index = $item['index'];

                if (empty($ip)) {
                    continue;
                }

                $task = TaskManager::getInstance()->runAsync(function () use ($ip, $currentPrivateKeyPath, $index) {
                    try {
                        $ssh = new \phpseclib3\Net\SSH2($ip);
                        $key = \phpseclib3\Crypt\PublicKeyLoader::loadPrivateKey(file_get_contents(
                            $currentPrivateKeyPath,
                        ));

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

                        // Run update & upgrade non-interactively and then output reboot + update status in one go
                        $statusOutput = trim($ssh->exec(
                            'apt-get update >/dev/null 2>&1 && '
                            . 'DEBIAN_FRONTEND=noninteractive apt-get -y upgrade >/dev/null 2>&1; '
                            . 'reboot_flag=$([ -f /var/run/reboot-required ] && echo yes || echo no); '
                            . 'updates=$(apt-get -s upgrade 2>/dev/null | grep -c "^Inst " || echo 0); '
                            . 'echo "$reboot_flag $updates"',
                        ));

                        $parts = preg_split('/\s+/', $statusOutput);
                        $rebootFlag = $parts[0] ?? 'no';
                        $updatesCount = isset($parts[1]) && is_numeric($parts[1]) ? (int) $parts[1] : 0;
                        $needsReboot = $rebootFlag === 'yes';

                        return [
                            'index' => $index,
                            'success' => true,
                            'updates' => $updatesCount,
                            'needs_reboot' => $needsReboot,
                        ];
                    } catch (\Throwable $e) {
                        return [
                            'index' => $index,
                            'success' => false,
                            'error' => 'SSH-Fehler: ' . $e->getMessage(),
                        ];
                    }
                });

                $task->onComplete(function ($result) use (&$serverListTab, $name) {
                    if (!is_array($result) || !array_key_exists('success', $result)) {
                        return;
                    }

                    $index = $result['index'] ?? null;
                    if ($index !== null && isset($serverListTab->currentServerData[$index])) {
                        if (isset($result['updates'])) {
                            $updates = (int) $result['updates'];
                            $serverListTab->currentServerData[$index]['updates_available'] = $updates > 0
                                ? 'ja (' . $updates . ')'
                                : 'nein';
                        }

                        if (array_key_exists('needs_reboot', $result)) {
                            $needsReboot = (bool) $result['needs_reboot'];
                            $serverListTab->currentServerData[$index]['needs_reboot'] = $needsReboot ? 'ja' : 'nein';
                        }
                        $searchTerm = strtolower(trim($serverListTab->searchInput->getValue()));
                        if (empty($searchTerm)) {
                            $serverListTab->table->updateData($serverListTab->currentServerData);
                        } else {
                            $filteredData = array_filter($serverListTab->currentServerData, function ($row) use (
                                $searchTerm,
                            ) {
                                if (str_contains(strtolower($row['name']), $searchTerm)) {
                                    return true;
                                }
                                $domains = $row['domains'] ?? [];
                                if (
                                    is_array($domains)
                                    && count(array_filter($domains, function ($item) use ($searchTerm) {
                                        return str_contains(strtolower($item), $searchTerm);
                                    }))
                                ) {
                                    return true;
                                }
                                $sshKeys = $row['ssh_keys'] ?? [];
                                if (
                                    is_array($sshKeys)
                                    && count(array_filter($sshKeys, function ($item) use ($searchTerm) {
                                        return str_contains(strtolower($item), $searchTerm);
                                    }))
                                ) {
                                    return true;
                                }
                                return false;
                            });
                            $serverListTab->table->updateData(array_values($filteredData));
                        }
                    }

                    if ($result['success']) {
                        $serverListTab->statusLabel->setText('Updates ausgeführt für ' . $name);
                        if (function_exists('desktop_notify')) {
                            desktop_notify('Update erfolgreich', 'Updates ausgeführt für ' . $name, [
                                'timeout' => 5000,
                                'urgency' => 'normal',
                            ]);
                        }
                    } elseif (isset($result['error'])) {
                        $serverListTab->statusLabel->setText('Update Fehler bei ' . $name . ': ' . $result['error']);
                        if (function_exists('desktop_notify')) {
                            desktop_notify('Update fehlgeschlagen', 'Fehler bei ' . $name . ': ' . $result['error'], [
                                'timeout' => 6000,
                                'urgency' => 'critical',
                            ]);
                        }
                    }
                });
            }
        });

        // Save per-server settings (API key, borgmatic passphrase + todos)
        $saveServerSettingsButton->setOnClick(function () use ($serverListTab) {
            if ($serverListTab->currentServerId === null) {
                $serverListTab->statusLabel->setText('Kein Server für das Speichern ausgewählt');
                return;
            }

            $settingsKeyBase = 'servers.' . $serverListTab->currentServerId;
            $apiKey = trim($serverListTab->serverApiKeyInput->getValue());
            $borgmaticPassphrase = trim($serverListTab->borgmaticPassphraseInput->getValue());

            $serverListTab->settings->set($settingsKeyBase . '.api_key', $apiKey);
            $serverListTab->settings->set($settingsKeyBase . '.borgmatic_passphrase', $borgmaticPassphrase);
            $serverListTab->settings->save();

            $serverListTab->statusLabel->setText('Server-Einstellungen gespeichert für Server #'
            . $serverListTab->currentServerId);
        });

        // Add TODO for current server
        $addTodoButton->setOnClick(function () use ($serverListTab) {
            if ($serverListTab->currentServerId === null) {
                $serverListTab->statusLabel->setText('Kein Server für TODO ausgewählt');
                return;
            }

            $text = trim($serverListTab->todoInput->getValue());
            if ($text === '') {
                return;
            }

            // Add as Kanban task in board "neu"
            $tasks = $serverListTab->settings->get('kanban.tasks', []);
            if (!is_array($tasks)) {
                $tasks = [];
            }

            $newTask = [
                'id' => uniqid('task_', true),
                'server_id' => $serverListTab->currentServerId,
                'title' => $text,
                'board' => 'neu',
            ];

            $tasks[] = $newTask;

            $serverListTab->settings->set('kanban.tasks', $tasks);
            $serverListTab->settings->save();

            $serverListTab->todoInput->setValue('');
            $serverListTab->loadServerTasks();

            if ($serverListTab->kanbanTab !== null) {
                $serverListTab->kanbanTab->refresh();
            }
        });
    }

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

    public function getSftpButton(): Button
    {
        return $this->sftpButton;
    }

    private static function fetchReleaseFromDomain(string $domain): string
    {
        $domain = trim($domain);
        if ($domain === '') {
            return 'unbekannt';
        }

        $url = $domain;
        if (!str_starts_with($url, 'http://') && !str_starts_with($url, 'https://')) {
            $url = 'https://' . $url;
        }

        $url = rtrim($url, '/') . '/apps/api/system/version';
        try {
            $context = stream_context_create([
                'http' => [
                    'method' => 'GET',
                    'timeout' => 5,
                ],
            ]);

            $response = file_get_contents($url, false, $context);
            if ($response === false) {
                return 'Fehler';
            }

            $data = json_decode($response, true);
            if (json_last_error() !== JSON_ERROR_NONE || !is_array($data)) {
                return 'Ungültig';
            }

            if (isset($data['version']) && is_string($data['version'])) {
                return $data['version'];
            }

            if (isset($data['release']) && is_string($data['release'])) {
                return $data['release'];
            }

            return 'unbekannt';
        } catch (\Throwable $e) {
            return 'Fehler';
        }
    }

    public function renderNeedsRebootCell(array $rowData, int $rowIndex): Label
    {
        $value = (string) ($rowData['needs_reboot'] ?? '');
        $normalized = strtolower(trim($value));

        $baseStyle = 'px-4 text-sm ';

        if ($normalized === 'nein') {
            $style = $baseStyle . 'text-green-600';
        } elseif ($normalized === 'ja') {
            $style = $baseStyle . 'text-red-600';
        } else {
            $style = $baseStyle . 'text-gray-600';
        }

        return new Label($value, $style);
    }

    public function renderUpdatesCell(array $rowData, int $rowIndex): Label
    {
        $value = (string) ($rowData['updates_available'] ?? '');
        $normalized = strtolower(trim($value));

        $baseStyle = 'px-4 text-sm ';

        if ($normalized === 'nein' || $normalized === 'nein (0)') {
            $style = $baseStyle . 'text-green-600';
        } elseif (str_starts_with($normalized, 'ja')) {
            $style = $baseStyle . 'text-red-600';
        } else {
            $style = $baseStyle . 'text-gray-600';
        }

        return new Label($value, $style);
    }

    public function renderTasksIndicatorCell(array $rowData, int $rowIndex): Label
    {
        $serverId = $rowData['id'] ?? null;
        $hasOpenTasks = false;

        if ($serverId !== null) {
            $tasks = $this->settings->get('kanban.tasks', []);
            if (is_array($tasks)) {
                $intServerId = (int) $serverId;
                $doneBoard = (string) $this->settings->get('kanban.done_board', 'fertig');
                foreach ($tasks as $task) {
                    if ((int) ($task['server_id'] ?? 0) === $intServerId) {
                        $taskBoard = (string) ($task['board'] ?? 'neu');
                        if ($taskBoard !== $doneBoard) {
                            $hasOpenTasks = true;
                            break;
                        }
                    }
                }
            }
        }

        $symbol = '●';
        $baseStyle = 'px-2 text-center text-sm ';
        $style = $baseStyle . ($hasOpenTasks ? 'text-red-500' : 'text-green-500');

        return new Label($symbol, $style);
    }

    public function renderDockerStatusCell(array $rowData, int $rowIndex): Label
    {
        $status = (string) ($rowData['docker_status'] ?? '');
        $hasError = strtolower(trim($status)) === 'error' || !empty($rowData['docker_error'] ?? null);

        $baseStyle = 'px-4 text-sm ';
        $style = $hasError ? $baseStyle . 'text-red-600' : $baseStyle . 'text-gray-800';

        return new Label($status, $style);
    }

    public function renderDockerRunningCell(array $rowData, int $rowIndex): Label
    {
        $value = $rowData['docker_running'] ?? 'unbekannt';
        $baseStyle = 'px-4 text-sm ';

        $style = $baseStyle . 'text-gray-800';
        $text = (string) $value;

        if (is_numeric($value)) {
            $count = (int) $value;
            $text = (string) $count;
            if ($count < 6) {
                $style = $baseStyle . 'text-red-600';
            }
        } else {
            $style = $baseStyle . 'text-gray-500 italic';
        }

        return new Label($text, $style);
    }

    public function renderOsVersionCell(array $rowData, int $rowIndex): Label
    {
        $value = (string) ($rowData['os_version'] ?? '');
        $normalized = strtolower(trim($value));

        $baseStyle = 'px-4 text-sm ';
        $style = $baseStyle . 'text-gray-800';

        if (preg_match('/ubuntu\s+(\d+)\./i', $value, $matches)) {
            $major = (int) ($matches[1] ?? 0);
            if ($major > 0 && $major < 24) {
                $style = $baseStyle . 'text-red-600';
            }
        }

        if ($normalized === 'unbekannt') {
            $style = $baseStyle . 'text-gray-500 italic';
        }

        return new Label($value, $style);
    }

    public function renderRootCell(array $rowData, int $rowIndex): Label
    {
        $value = (string) ($rowData['root'] ?? '');
        return $this->renderDiskUsageCell($value);
    }

    public function renderDataCell(array $rowData, int $rowIndex): Label
    {
        $value = (string) ($rowData['data'] ?? '');
        return $this->renderDiskUsageCell($value);
    }

    private function renderDiskUsageCell(string $value): Label
    {
        $trimmed = trim($value);
        $baseStyle = 'px-4 text-sm ';

        $style = $baseStyle . 'text-gray-800';

        if ($trimmed === '' || strtolower($trimmed) === 'unbekannt') {
            $style = $baseStyle . 'text-gray-500 italic';
        } else {
            $numeric = $trimmed;
            if (str_ends_with($numeric, '%')) {
                $numeric = substr($numeric, 0, -1);
            }
            if (is_numeric($numeric) && (int) $numeric >= 90) {
                $style = $baseStyle . 'text-red-600';
            }
        }

        return new Label($value, $style);
    }

    public function renderLastBackupCell(array $rowData, int $rowIndex): Label
    {
        $value = (string) ($rowData['last_backup'] ?? 'unbekannt');
        $normalized = strtolower(trim($value));

        $baseStyle = 'px-4 text-sm ';

        if ($normalized === 'unbekannt' || $normalized === '') {
            $style = $baseStyle . 'text-gray-500 italic';
            return new Label($value, $style);
        }

        // Check if backup is older than 24 hours
        try {
            $backupTime = \DateTime::createFromFormat('d.m.Y H:i', $value);
            if ($backupTime !== false) {
                $now = new \DateTime();
                $diff = $now->diff($backupTime);
                $hoursAgo = ($diff->days * 24) + $diff->h;

                if ($hoursAgo > 24) {
                    $style = $baseStyle . 'text-red-600';
                } else {
                    $style = $baseStyle . 'text-green-600';
                }
            } else {
                $style = $baseStyle . 'text-gray-800';
            }
        } catch (\Exception $e) {
            $style = $baseStyle . 'text-gray-800';
        }

        return new Label($value, $style);
    }

    public function renderSshKeysCell(array $rowData, int $rowIndex): Label
    {
        $sshKeys = $rowData['ssh_keys'] ?? [];
        $count = is_array($sshKeys) ? count($sshKeys) : 0;

        $baseStyle = 'px-4 text-sm text-center ';

        if ($count === 0) {
            $style = $baseStyle . 'text-gray-500 italic';
            return new Label('0', $style);
        }

        $style = $baseStyle . 'text-blue-600 font-semibold';
        return new Label((string) $count, $style);
    }

    private function updateDomainDetails(array $domains): void
    {
        $this->detailDomainsContainer->clearChildren();

        if (empty($domains)) {
            $this->detailDomainsContainer->addComponent(new Label(
                'Keine Domains gefunden',
                'text-xs text-gray-500 italic',
            ));
            return;
        }

        foreach ($domains as $domain) {
            if (!is_string($domain) || trim($domain) === '') {
                continue;
            }

            $domain = trim($domain);
            $button = new Button($domain, 'text-sm text-blue-600 hover:text-blue-800 underline text-left');

            $button->setOnClick(function () use ($domain) {
                $url = $domain;
                if (!str_starts_with($url, 'http://') && !str_starts_with($url, 'https://')) {
                    $url = 'https://' . $url;
                }

                // Versuche, die Domain im Standardbrowser zu öffnen (Linux-Umgebung)
                $escapedUrl = escapeshellarg($url);
                exec("xdg-open {$escapedUrl} > /dev/null 2>&1 &");
            });

            $this->detailDomainsContainer->addComponent($button);
        }
    }

    private function updateSshKeysDetails(array $sshKeys): void
    {
        $this->detailSshKeysContainer->clearChildren();

        if (empty($sshKeys)) {
            $this->detailSshKeysContainer->addComponent(new Label(
                'Keine SSH Keys gefunden',
                'text-xs text-gray-500 italic',
            ));
            return;
        }

        foreach ($sshKeys as $key) {
            if (!is_string($key) || trim($key) === '') {
                continue;
            }

            $key = trim($key);
            // Extract key type and comment/fingerprint for display
            $parts = explode(' ', $key, 3);
            $keyType = $parts[0] ?? 'unknown';
            $keyFingerprint = isset($parts[1]) ? substr($parts[1], 0, 20) . '...' : '';
            $keyComment = $parts[2] ?? '';

            $displayText = $keyType . ' ' . $keyFingerprint;
            if ($keyComment !== '') {
                $displayText .= ' (' . $keyComment . ')';
            }

            $keyLabel = new Label($displayText, 'text-xs text-gray-700 font-mono break-all');
            $this->detailSshKeysContainer->addComponent($keyLabel);
        }
    }

    private function renderTodoList(): void
    {
        $this->todoListContainer->clearChildren();

        if (empty($this->currentServerTodos)) {
            $this->todoListContainer->addComponent(new Label('Keine Tasks', 'text-xs text-gray-500 italic'));
            return;
        }

        foreach ($this->currentServerTodos as $index => $task) {
            $title = (string) ($task['title'] ?? '');
            $board = (string) ($task['board'] ?? 'neu');

            $row = new Container('flex flex-row items-center gap-2');
            $row->addComponent(new Label('- ' . $title . ' [' . $board . ']', 'text-xs text-gray-800 flex-1'));

            $removeButton = new Button(
                'x',
                'px-2 py-1 bg-red-500 rounded hover:bg-red-600',
                null,
                'text-white text-xs',
            );

            $serverListTab = $this;
            $removeButton->setOnClick(function () use ($serverListTab, $task) {
                $taskId = $task['id'] ?? null;
                if ($taskId === null) {
                    return;
                }

                $tasks = $serverListTab->settings->get('kanban.tasks', []);
                if (!is_array($tasks)) {
                    return;
                }

                $tasks = array_values(array_filter($tasks, static fn($t) => ($t['id'] ?? null) !== $taskId));

                $serverListTab->settings->set('kanban.tasks', $tasks);
                $serverListTab->settings->save();
                $serverListTab->loadServerTasks();

                if ($serverListTab->kanbanTab !== null) {
                    $serverListTab->kanbanTab->refresh();
                }
            });

            $row->addComponent($removeButton);
            $this->todoListContainer->addComponent($row);
        }
    }

    public function renderSelectCell(array $rowData, int $rowIndex): Checkbox
    {
        $isChecked = (bool) ($rowData['selected'] ?? false);
        $checkbox = new Checkbox('', $isChecked);

        $serverListTab = $this;
        $rowId = $rowData['id'] ?? null;
        $checkbox->setOnChange(function (bool $checked) use (&$serverListTab, &$rowData, $rowId) {
            if ($rowId === null) {
                return;
            }

            foreach ($serverListTab->currentServerData as $index => $row) {
                if (($row['id'] ?? null) === $rowId) {
                    $serverListTab->currentServerData[$index]['selected'] = $checked;
                    $serverListTab->table->updateData($serverListTab->currentServerData);
                    break;
                }
            }
        });

        return $checkbox;
    }

    private function loadServerTasks(): void
    {
        $this->currentServerTodos = [];

        if ($this->currentServerId === null) {
            $this->renderTodoList();
            return;
        }

        $tasks = $this->settings->get('kanban.tasks', []);
        if (!is_array($tasks)) {
            $tasks = [];
        }

        $this->currentServerTodos = array_values(array_filter($tasks, function ($task) {
            return (int) ($task['server_id'] ?? 0) === (int) $this->currentServerId;
        }));

        $this->renderTodoList();
    }

    public function refreshCurrentServerTasks(): void
    {
        $this->loadServerTasks();
    }
}
