<?php

namespace ServerManager\UI;

use PHPNative\Async\TaskManager;
use PHPNative\Tailwind\Data\Icon as IconName;
use PHPNative\Ui\Widget\Button;
use PHPNative\Ui\Widget\Container;
use PHPNative\Ui\Widget\Icon;
use PHPNative\Ui\Widget\Label;
use PHPNative\Ui\Widget\TabContainer;
use PHPNative\Ui\Widget\Table;
use PHPNative\Ui\Widget\TextInput;
use ServerManager\Services\HetznerService;

class ServerListTab
{
    private Container $tab;
    private Table $table;
    private TextInput $searchInput;
    private Label $statusLabel;
    private Button $refreshButton;
    private Button $sftpButton;
    private Button $sshTerminalButton;

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

    private Label $detailId;
    private Label $detailName;
    private Label $detailStatus;
    private Label $detailType;
    private Label $detailIpv4;
    private Container $detailDomainsContainer;

    public function __construct(
        string &$apiKey,
        string &$privateKeyPath,
        TabContainer $tabContainer,
        Label $statusLabel,
    ) {
        $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');

        // 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);
        $leftSide->addComponent($this->refreshButton);

        // 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
        $this->table = new Table(style: ' flex-1');
        $this->table->setColumns([
            ['key' => 'id', 'title' => 'ID', 'width' => 80],
            ['key' => 'name', 'title' => 'Name'],
            ['key' => 'status', 'title' => 'Status', 'width' => 100],
            ['key' => 'type', 'title' => 'Typ', 'width' => 80],
            ['key' => 'ipv4', 'title' => 'IPv4', 'width' => 160],
            ['key' => 'docker_status', 'title' => 'Docker', 'width' => 100],
        ]);

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

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

        // Right side: Detail panel
        $detailPanel = new Container('flex flex-col gap-3 w-120 bg-white border-2 border-gray-300 rounded p-4');
        $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);

        // 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 = [
                '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);

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

        // Setup event handlers
        $this->setupEventHandlers($currentApiKey, $currentPrivateKeyPath);
    }

    private function setupEventHandlers(string &$currentApiKey, string &$currentPrivateKeyPath): 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']);

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

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

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

            if (empty($searchTerm)) {
                $serverListTab->table->setData($serverListTab->currentServerData);
            } else {
                $filteredData = array_filter($serverListTab->currentServerData, function ($row) use ($searchTerm) {
                    return (
                        str_contains(strtolower($row['name']), $searchTerm) ||
                        count(array_filter($row['domains'], function ($item) use ($searchTerm) {
                            return str_contains(strtolower($item), $searchTerm);
                        }))
                    );
                });
                $serverListTab->table->setData(array_values($filteredData));
            }
        });

        // Refresh button - use reference to apiKey & privateKey variable
        $this->refreshButton->setOnClickAsync(
            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()];
                }
            },
            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' => null,
                            'docker_error' => null,
                        ], $row), $result['servers']);

                        $serverListTab->table->setData($serverListTab->currentServerData);
                        $serverListTab->statusLabel->setText('Server geladen: ' . $result['count'] . ' gefunden');
                        echo "Success: {$result['count']} servers loaded\n";

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

                            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';
                                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,
                                            'docker' => null,
                                            'docker_error' => 'SSH Login fehlgeschlagen',
                                            'docker_status' => 'error',
                                        ];
                                    }

                                    $output = $ssh->exec('docker inspect psc-web-1');

                                    if (empty($output)) {
                                        return [
                                            'index' => $index,
                                            'docker' => null,
                                            'docker_error' => 'Leere Docker-Antwort',
                                            'docker_status' => 'error',
                                        ];
                                    }

                                    $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',
                                        ];
                                    }

                                    return [
                                        'index' => $index,
                                        'docker' => $json,
                                        'docker_error' => null,
                                        'docker_status' => 'ok',
                                    ];
                                } catch (\Throwable $e) {
                                    return [
                                        'index' => $index,
                                        'docker' => null,
                                        'docker_error' => 'SSH-Fehler: ' . $e->getMessage(),
                                        'docker_status' => 'error',
                                    ];
                                }
                            });

                            $task->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)) {
                                    if (isset($dockerResult['docker'][0]['Config']['Env'])) {
                                        $hosts = array_filter(
                                            $dockerResult['docker'][0]['Config']['Env'],
                                            function ($item) {
                                                if (str_starts_with($item, 'LETSENCRYPT_HOST')) {
                                                    return true;
                                                }
                                                return false;
                                            },
                                        );
                                        $domains = explode(
                                            ',',
                                            substr(array_first($hosts), strlen('LETSENCRYPT_HOST=')),
                                        );

                                        $serverListTab->currentServerData[$i]['domains'] = $domains;
                                    }
                                    $serverListTab->currentServerData[$i]['docker'] = $dockerResult['docker'];
                                    $serverListTab->table->setData($serverListTab->currentServerData);
                                }

                                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'];
                                }
                            });

                            $task->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;
                                }
                            });
                        }
                    }
                }
            },
            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";
            },
        );
    }

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

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

    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);
        }
    }
}
