<?php

namespace App\Livewire\Server;

use App\Actions\Server\StartSentinel;
use App\Actions\Server\StopSentinel;
use App\Events\ServerReachabilityChanged;
use App\Models\CloudProviderToken;
use App\Models\Server;
use App\Rules\ValidServerIp;
use App\Services\DigitalOceanService;
use App\Services\HetznerService;
use App\Services\VultrService;
use App\Support\ValidationPatterns;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Support\Collection;
use Livewire\Attributes\Computed;
use Livewire\Attributes\Locked;
use Livewire\Component;

class Show extends Component
{
    use AuthorizesRequests;

    public Server $server;

    public string $name;

    public ?string $description = null;

    public string $ip;

    public string $user;

    public string $port;

    public int $connectionTimeout;

    public ?string $validationLogs = null;

    public ?string $wildcardDomain = null;

    public bool $isReachable;

    public bool $isUsable;

    public bool $isSwarmManager;

    public bool $isSwarmWorker;

    public bool $isBuildServer;

    #[Locked]
    public bool $isBuildServerLocked = false;

    public bool $isMetricsEnabled;

    public string $sentinelToken;

    public ?string $sentinelUpdatedAt = null;

    public int $sentinelMetricsRefreshRateSeconds;

    public int $sentinelMetricsHistoryDays;

    public int $sentinelPushIntervalSeconds;

    public ?string $sentinelCustomUrl = null;

    public bool $isSentinelEnabled;

    public bool $isSentinelDebugEnabled;

    public ?string $sentinelCustomDockerImage = null;

    public string $serverTimezone;

    public ?string $hetznerServerStatus = null;

    public ?string $vultrInstanceStatus = null;

    public ?string $digitalOceanDropletStatus = null;

    public bool $hetznerServerManuallyStarted = false;

    public bool $vultrInstanceManuallyStarted = false;

    public bool $digitalOceanDropletManuallyStarted = false;

    public bool $isValidating = false;

    // Hetzner linking properties
    public Collection $availableHetznerTokens;

    public ?int $selectedHetznerTokenId = null;

    public ?string $manualHetznerServerId = null;

    public ?array $matchedHetznerServer = null;

    public ?string $hetznerSearchError = null;

    public bool $hetznerNoMatchFound = false;

    public Collection $availableVultrTokens;

    public ?int $selectedVultrTokenId = null;

    public ?string $manualVultrInstanceId = null;

    public ?array $matchedVultrInstance = null;

    public ?string $vultrSearchError = null;

    public bool $vultrNoMatchFound = false;

    public Collection $availableDigitalOceanTokens;

    public ?int $selectedDigitalOceanTokenId = null;

    public ?string $manualDigitalOceanDropletId = null;

    public ?array $matchedDigitalOceanDroplet = null;

    public ?string $digitalOceanSearchError = null;

    public bool $digitalOceanNoMatchFound = false;

    public function getListeners()
    {
        $teamId = $this->server->team_id ?? auth()->user()->currentTeam()->id;

        return [
            'refreshServerShow' => 'refresh',
            'refreshServer' => '$refresh',
            "echo-private:team.{$teamId},SentinelRestarted" => 'handleSentinelRestarted',
            "echo-private:team.{$teamId},ServerValidated" => 'handleServerValidated',
        ];
    }

    protected function rules(): array
    {
        return [
            'name' => ValidationPatterns::nameRules(),
            'description' => ValidationPatterns::descriptionRules(),
            'ip' => ['required', new ValidServerIp],
            'user' => ValidationPatterns::serverUsernameRules(),
            'port' => 'required|integer|between:1,65535',
            'connectionTimeout' => 'required|integer|min:1|max:300',
            'validationLogs' => 'nullable',
            'wildcardDomain' => 'nullable|url',
            'isReachable' => 'required',
            'isUsable' => 'required',
            'isSwarmManager' => 'required',
            'isSwarmWorker' => 'required',
            'isBuildServer' => 'required',
            'isMetricsEnabled' => 'required',
            'sentinelToken' => 'required',
            'sentinelUpdatedAt' => 'nullable',
            'sentinelMetricsRefreshRateSeconds' => 'required|integer|min:1',
            'sentinelMetricsHistoryDays' => 'required|integer|min:1',
            'sentinelPushIntervalSeconds' => 'required|integer|min:10',
            'sentinelCustomUrl' => 'nullable|url',
            'isSentinelEnabled' => 'required',
            'isSentinelDebugEnabled' => 'required',
            'serverTimezone' => 'required',
        ];
    }

    protected function messages(): array
    {
        return array_merge(
            ValidationPatterns::combinedMessages(),
            [
                'ip.required' => 'The IP Address field is required.',
                'user.required' => 'The User field is required.',
                ...ValidationPatterns::serverUsernameMessages(),
                'port.required' => 'The Port field is required.',
                'connectionTimeout.required' => 'The SSH Connection Timeout field is required.',
                'connectionTimeout.integer' => 'The SSH Connection Timeout must be an integer.',
                'connectionTimeout.min' => 'The SSH Connection Timeout must be at least 1 second.',
                'connectionTimeout.max' => 'The SSH Connection Timeout must not exceed 300 seconds.',
                'wildcardDomain.url' => 'The Wildcard Domain must be a valid URL.',
                'sentinelToken.required' => 'The Sentinel Token field is required.',
                'sentinelMetricsRefreshRateSeconds.required' => 'The Metrics Refresh Rate field is required.',
                'sentinelMetricsRefreshRateSeconds.integer' => 'The Metrics Refresh Rate must be an integer.',
                'sentinelMetricsRefreshRateSeconds.min' => 'The Metrics Refresh Rate must be at least 1 second.',
                'sentinelMetricsHistoryDays.required' => 'The Metrics History Days field is required.',
                'sentinelMetricsHistoryDays.integer' => 'The Metrics History Days must be an integer.',
                'sentinelMetricsHistoryDays.min' => 'The Metrics History Days must be at least 1 day.',
                'sentinelPushIntervalSeconds.required' => 'The Push Interval field is required.',
                'sentinelPushIntervalSeconds.integer' => 'The Push Interval must be an integer.',
                'sentinelPushIntervalSeconds.min' => 'The Push Interval must be at least 10 seconds.',
                'sentinelCustomUrl.url' => 'The Custom Sentinel URL must be a valid URL.',
                'serverTimezone.required' => 'The Server Timezone field is required.',
            ]
        );
    }

    public function mount(string $server_uuid)
    {
        try {
            $this->server = Server::ownedByCurrentTeam()->whereUuid($server_uuid)->firstOrFail();
            $this->syncData();
            if (! $this->server->isEmpty()) {
                $this->isBuildServerLocked = true;
            }
            // Load saved Hetzner status and validation state
            $this->hetznerServerStatus = $this->server->hetzner_server_status;
            $this->vultrInstanceStatus = $this->server->vultr_instance_status;
            $this->digitalOceanDropletStatus = $this->server->digitalocean_droplet_status;
            $this->isValidating = $this->server->is_validating ?? false;

            // Load cloud provider tokens for linking
            $this->loadHetznerTokens();
            $this->loadVultrTokens();
            $this->loadDigitalOceanTokens();

        } catch (\Throwable $e) {
            return handleError($e, $this);
        }
    }

    #[Computed]
    public function timezones(): array
    {
        return collect(timezone_identifiers_list())
            ->sort()
            ->values()
            ->toArray();
    }

    public function syncData(bool $toModel = false)
    {
        if ($toModel) {
            $this->validate();

            $this->authorize('update', $this->server);
            $foundServer = Server::where('ip', $this->ip)
                ->where('id', '!=', $this->server->id)
                ->first();
            if ($foundServer) {
                $this->ip = $this->server->ip;
                if ($foundServer->team_id === currentTeam()->id) {
                    throw new \Exception('A server with this IP/Domain already exists in your team.');
                }

                throw new \Exception('A server with this IP/Domain is already in use by another team.');
            }

            $this->server->name = $this->name;
            $this->server->description = $this->description;
            $this->server->ip = $this->ip;
            $this->server->user = $this->user;
            $this->server->port = $this->port;
            $this->server->validation_logs = $this->validationLogs;
            $this->server->save();

            $this->server->settings->connection_timeout = $this->connectionTimeout;
            $this->server->settings->is_swarm_manager = $this->isSwarmManager;
            $this->server->settings->wildcard_domain = $this->wildcardDomain;
            $this->server->settings->is_swarm_worker = $this->isSwarmWorker;
            $this->server->settings->is_build_server = $this->isBuildServer;
            $this->server->settings->is_metrics_enabled = $this->isMetricsEnabled;
            $this->server->settings->sentinel_token = $this->sentinelToken;
            $this->server->settings->sentinel_metrics_refresh_rate_seconds = $this->sentinelMetricsRefreshRateSeconds;
            $this->server->settings->sentinel_metrics_history_days = $this->sentinelMetricsHistoryDays;
            $this->server->settings->sentinel_push_interval_seconds = $this->sentinelPushIntervalSeconds;
            $this->server->settings->sentinel_custom_url = $this->sentinelCustomUrl;
            $this->server->settings->is_sentinel_enabled = $this->isSentinelEnabled;
            $this->server->settings->is_sentinel_debug_enabled = $this->isSentinelDebugEnabled;

            if (! validate_timezone($this->serverTimezone)) {
                $this->serverTimezone = config('app.timezone');
                throw new \Exception('Invalid timezone.');
            } else {
                $this->server->settings->server_timezone = $this->serverTimezone;
            }

            $this->server->settings->save();
        } else {
            $this->name = $this->server->name;
            $this->description = $this->server->description;
            $this->ip = $this->server->ip;
            $this->user = $this->server->user;
            $this->port = $this->server->port;
            $this->connectionTimeout = $this->server->settings->connection_timeout;

            $this->wildcardDomain = $this->server->settings->wildcard_domain;
            $this->isReachable = $this->server->settings->is_reachable;
            $this->isUsable = $this->server->settings->is_usable;
            $this->isSwarmManager = $this->server->settings->is_swarm_manager;
            $this->isSwarmWorker = $this->server->settings->is_swarm_worker;
            $this->isBuildServer = $this->server->settings->is_build_server;
            $this->isMetricsEnabled = $this->server->settings->is_metrics_enabled;
            $this->sentinelToken = $this->server->settings->sentinel_token;
            $this->sentinelMetricsRefreshRateSeconds = $this->server->settings->sentinel_metrics_refresh_rate_seconds;
            $this->sentinelMetricsHistoryDays = $this->server->settings->sentinel_metrics_history_days;
            $this->sentinelPushIntervalSeconds = $this->server->settings->sentinel_push_interval_seconds;
            $this->sentinelCustomUrl = $this->server->settings->sentinel_custom_url;
            $this->isSentinelEnabled = $this->server->settings->is_sentinel_enabled;
            $this->isSentinelDebugEnabled = $this->server->settings->is_sentinel_debug_enabled;
            $this->sentinelUpdatedAt = $this->server->sentinel_updated_at;
            $this->serverTimezone = $this->server->settings->server_timezone;
            $this->isValidating = $this->server->is_validating ?? false;
        }
    }

    public function refresh()
    {
        $this->syncData();
    }

    public function handleSentinelRestarted($event)
    {
        // Only refresh if the event is for this server
        if (isset($event['serverUuid']) && $event['serverUuid'] === $this->server->uuid) {
            $this->server->refresh();
            // Only refresh display-only state; never re-sync text-input properties
            // (would clobber any unsaved typing — see coolify#6062 / #6354 / #9695).
            $this->sentinelUpdatedAt = $this->server->sentinel_updated_at;
            $this->dispatch('success', 'Sentinel has been restarted successfully.');
        }
    }

    public function validateServer($install = true)
    {
        try {
            $this->authorize('update', $this->server);
            if ($this->server->vultr_instance_id) {
                $status = $this->server->refreshVultrState();
                $this->server->refresh();
                $this->vultrInstanceStatus = $this->server->vultr_instance_status;
                $this->ip = $this->server->ip;

                if (in_array($status, ['stopped', 'suspended', 'deleted'], true)) {
                    $message = $status === 'deleted'
                        ? 'Vultr instance is deleted or no longer accessible. Relink this server before validating.'
                        : 'Vultr instance is '.($status ?? 'not running').'. Power it on before validating.';
                    $this->dispatch('error', $message);

                    return;
                }
            }

            $this->validationLogs = $this->server->validation_logs = null;
            $this->server->save();
            $this->dispatch('init', $install);
        } catch (\Throwable $e) {
            return handleError($e, $this);
        }
    }

    public function checkLocalhostConnection()
    {
        try {
            $this->syncData(true);
            ['uptime' => $uptime, 'error' => $error] = $this->server->validateConnection();
            if ($uptime) {
                $this->dispatch('success', 'Server is reachable.');
                $this->server->settings->is_reachable = $this->isReachable = true;
                $this->server->settings->is_usable = $this->isUsable = true;
                $this->server->settings->save();
                ServerReachabilityChanged::dispatch($this->server);
            } else {
                $this->dispatch('error', 'Server is not reachable.', 'Please validate your configuration and connection.<br><br>Check this <a target="_blank" class="underline" href="https://coolify.io/docs/knowledge-base/server/openssh">documentation</a> for further help. <br><br>Error: '.$error);

                return;
            }
        } catch (\Throwable $e) {
            return handleError($e, $this);
        }
    }

    public function restartSentinel()
    {
        try {
            $this->authorize('manageSentinel', $this->server);
            $customImage = isDev() ? $this->sentinelCustomDockerImage : null;
            $this->server->restartSentinel($customImage);
            $this->dispatch('info', 'Restarting Sentinel.');
        } catch (\Throwable $e) {
            return handleError($e, $this);
        }

    }

    public function updatedIsSentinelDebugEnabled($value)
    {
        try {
            $this->submit();
            $this->restartSentinel();
        } catch (\Throwable $e) {
            return handleError($e, $this);
        }
    }

    public function updatedIsMetricsEnabled($value)
    {
        try {
            $this->submit();
            $this->restartSentinel();
        } catch (\Throwable $e) {
            return handleError($e, $this);
        }
    }

    public function updatedIsBuildServer($value)
    {
        try {
            $this->authorize('update', $this->server);
            if ($value === true && $this->isSentinelEnabled) {
                $this->isSentinelEnabled = false;
                $this->isMetricsEnabled = false;
                $this->isSentinelDebugEnabled = false;
                StopSentinel::dispatch($this->server);
                $this->dispatch('info', 'Sentinel has been disabled as build servers cannot run Sentinel.');
            }
            $this->submit();
            // Dispatch event to refresh the navbar
            $this->dispatch('refreshServerShow');
        } catch (\Throwable $e) {
            return handleError($e, $this);
        }
    }

    public function updatedIsSentinelEnabled($value)
    {
        try {
            $this->authorize('manageSentinel', $this->server);
            if ($value === true) {
                if ($this->isBuildServer) {
                    $this->isSentinelEnabled = false;
                    $this->dispatch('error', 'Sentinel cannot be enabled on build servers.');

                    return;
                }
                $customImage = isDev() ? $this->sentinelCustomDockerImage : null;
                StartSentinel::run($this->server, true, null, $customImage);
            } else {
                $this->isMetricsEnabled = false;
                $this->isSentinelDebugEnabled = false;
                StopSentinel::dispatch($this->server);
            }
            $this->submit();
        } catch (\Throwable $e) {
            return handleError($e, $this);
        }
    }

    public function regenerateSentinelToken()
    {
        try {
            $this->authorize('manageSentinel', $this->server);
            $this->server->settings->generateSentinelToken();
            $this->dispatch('success', 'Token regenerated. Restarting Sentinel.');
        } catch (\Throwable $e) {
            return handleError($e, $this);
        }
    }

    public function instantSave()
    {
        try {
            $this->syncData(true);
        } catch (\Throwable $e) {
            return handleError($e, $this);
        }
    }

    public function checkHetznerServerStatus(bool $manual = false)
    {
        try {
            $this->authorize('view', $this->server);
            if (! $this->server->hetzner_server_id || ! $this->server->cloudProviderToken) {
                $this->dispatch('error', 'This server is not associated with a Hetzner Cloud server or token.');

                return;
            }

            $hetznerService = new HetznerService($this->server->cloudProviderToken->token);
            $serverData = $hetznerService->getServer($this->server->hetzner_server_id);

            $this->hetznerServerStatus = $serverData['status'] ?? null;

            // Save status to database without triggering model events
            if ($this->server->hetzner_server_status !== $this->hetznerServerStatus) {
                $this->server->hetzner_server_status = $this->hetznerServerStatus;
                $this->server->update(['hetzner_server_status' => $this->hetznerServerStatus]);
            }
            if ($manual) {
                $this->dispatch('success', 'Server status refreshed: '.ucfirst($this->hetznerServerStatus ?? 'unknown'));
            }

            // If Hetzner server is off but Coolify thinks it's still reachable, update Coolify's state
            if ($this->hetznerServerStatus === 'off' && $this->server->settings->is_reachable) {
                ['uptime' => $uptime, 'error' => $error] = $this->server->validateConnection();
                if ($uptime) {
                    $this->dispatch('success', 'Server is reachable.');
                    $this->server->settings->is_reachable = $this->isReachable = true;
                    $this->server->settings->is_usable = $this->isUsable = true;
                    $this->server->settings->save();
                    ServerReachabilityChanged::dispatch($this->server);
                } else {
                    $this->dispatch('error', 'Server is not reachable.', 'Please validate your configuration and connection.<br><br>Check this <a target="_blank" class="underline" href="https://coolify.io/docs/knowledge-base/server/openssh">documentation</a> for further help. <br><br>Error: '.$error);

                    return;
                }
            }
        } catch (\Throwable $e) {
            return handleError($e, $this);
        }
    }

    public function checkVultrInstanceStatus(bool $manual = false)
    {
        try {
            if (! $this->server->vultr_instance_id || ! $this->server->cloudProviderToken) {
                $this->dispatch('error', 'This server is not associated with a Vultr instance or token.');

                return;
            }

            $this->vultrInstanceStatus = $this->server->refreshVultrState();
            $this->server->refresh();
            $this->ip = $this->server->ip;

            if ($manual) {
                $this->dispatch('success', 'Instance status refreshed: '.ucfirst($this->vultrInstanceStatus ?? 'unknown'));
            }
        } catch (\Throwable $e) {
            return handleError($e, $this);
        }
    }

    public function checkDigitalOceanDropletStatus(bool $manual = false)
    {
        try {
            $this->authorize('view', $this->server);
            if (! $this->server->digitalocean_droplet_id || ! $this->server->cloudProviderToken) {
                $this->dispatch('error', 'This server is not associated with a DigitalOcean droplet or token.');

                return;
            }

            $this->digitalOceanDropletStatus = $this->server->refreshDigitalOceanState();
            $this->server->refresh();
            $this->ip = $this->server->ip;

            if ($manual) {
                $this->dispatch('success', 'Droplet status refreshed: '.ucfirst($this->digitalOceanDropletStatus ?? 'unknown'));
            }
        } catch (\Throwable $e) {
            return handleError($e, $this);
        }
    }

    public function handleServerValidated($event = null)
    {
        // Check if event is for this server
        if ($event && isset($event['serverUuid']) && $event['serverUuid'] !== $this->server->uuid) {
            return;
        }

        // Refresh server data and only the display-only state that validation produces.
        // Never re-sync text-input properties via syncData() — would clobber any
        // unsaved typing (see coolify#6062 / #6354 / #9695).
        $this->server->refresh();
        $this->server->settings->refresh();
        $this->isValidating = $this->server->is_validating ?? false;
        $this->validationLogs = $this->server->validation_logs;
        $this->isReachable = $this->server->settings->is_reachable;
        $this->isUsable = $this->server->settings->is_usable;

        // Reload Hetzner tokens in case the linking section should now be shown
        $this->loadHetznerTokens();
        $this->loadVultrTokens();
        $this->loadDigitalOceanTokens();

        $this->dispatch('refreshServerShow');
        $this->dispatch('refreshServer');
    }

    public function startHetznerServer()
    {
        try {
            $this->authorize('update', $this->server);
            if (! $this->server->hetzner_server_id || ! $this->server->cloudProviderToken) {
                $this->dispatch('error', 'This server is not associated with a Hetzner Cloud server or token.');

                return;
            }

            $hetznerService = new HetznerService($this->server->cloudProviderToken->token);
            $hetznerService->powerOnServer($this->server->hetzner_server_id);

            $this->hetznerServerStatus = 'starting';
            $this->server->update(['hetzner_server_status' => 'starting']);
            $this->hetznerServerManuallyStarted = true; // Set flag to trigger auto-validation when running
            $this->dispatch('success', 'Hetzner server is starting...');
        } catch (\Throwable $e) {
            return handleError($e, $this);
        }
    }

    public function startVultrInstance()
    {
        try {
            if (! $this->server->vultr_instance_id || ! $this->server->cloudProviderToken) {
                $this->dispatch('error', 'This server is not associated with a Vultr instance or token.');

                return;
            }

            $vultrService = new VultrService($this->server->cloudProviderToken->token);
            $vultrService->startInstance($this->server->vultr_instance_id);

            $this->vultrInstanceStatus = 'starting';
            $this->server->update(['vultr_instance_status' => 'starting']);
            $this->vultrInstanceManuallyStarted = true;
            $this->dispatch('success', 'Vultr instance is starting...');
        } catch (\Throwable $e) {
            return handleError($e, $this);
        }
    }

    public function startDigitalOceanDroplet()
    {
        try {
            $this->authorize('update', $this->server);
            if (! $this->server->digitalocean_droplet_id || ! $this->server->cloudProviderToken) {
                $this->dispatch('error', 'This server is not associated with a DigitalOcean droplet or token.');

                return;
            }

            $digitalOceanService = new DigitalOceanService($this->server->cloudProviderToken->token);
            $digitalOceanService->powerOnDroplet((int) $this->server->digitalocean_droplet_id);

            $this->digitalOceanDropletStatus = 'new';
            $this->server->update(['digitalocean_droplet_status' => 'new']);
            $this->digitalOceanDropletManuallyStarted = true;
            $this->dispatch('success', 'DigitalOcean droplet is starting...');
        } catch (\Throwable $e) {
            return handleError($e, $this);
        }
    }

    public function refreshServerMetadata(): void
    {
        try {
            $this->authorize('update', $this->server);
            $result = $this->server->gatherServerMetadata();
            if ($result) {
                $this->server->refresh();
                $this->dispatch('success', 'Server details refreshed.');
            } else {
                $this->dispatch('error', 'Could not fetch server details. Is the server reachable?');
            }
        } catch (\Throwable $e) {
            handleError($e, $this);
        }
    }

    public function submit()
    {
        try {
            $this->syncData(true);
            $this->dispatch('success', 'Server settings updated.');
        } catch (\Throwable $e) {
            return handleError($e, $this);
        }
    }

    public function loadHetznerTokens(): void
    {
        $this->availableHetznerTokens = CloudProviderToken::ownedByCurrentTeam()
            ->where('provider', 'hetzner')
            ->get();
    }

    public function loadVultrTokens(): void
    {
        $this->availableVultrTokens = CloudProviderToken::ownedByCurrentTeam()
            ->where('provider', 'vultr')
            ->get();
    }

    public function loadDigitalOceanTokens(): void
    {
        $this->availableDigitalOceanTokens = CloudProviderToken::ownedByCurrentTeam()
            ->where('provider', 'digitalocean')
            ->get();
    }

    #[Computed]
    public function limaStartCommand(): ?string
    {
        if (! isDev()) {
            return null;
        }

        return match ($this->server->uuid) {
            'lima-ubuntu-2404' => 'limactl start --yes --name=coolify-lima-ubuntu-2404 docker/lima/ubuntu-2404.yaml',
            'lima-ubuntu-2604' => 'limactl start --yes --name=coolify-lima-ubuntu-2604 docker/lima/ubuntu-2604.yaml',
            default => null,
        };
    }

    public function searchHetznerServer(): void
    {
        $this->hetznerSearchError = null;
        $this->hetznerNoMatchFound = false;
        $this->matchedHetznerServer = null;

        if (! $this->selectedHetznerTokenId) {
            $this->hetznerSearchError = 'Please select a Hetzner token.';

            return;
        }

        try {
            $this->authorize('update', $this->server);

            $token = $this->availableHetznerTokens->firstWhere('id', $this->selectedHetznerTokenId);
            if (! $token) {
                $this->hetznerSearchError = 'Invalid token selected.';

                return;
            }

            $hetznerService = new HetznerService($token->token);
            $matched = $hetznerService->findServerByIp($this->server->ip);

            if ($matched) {
                $this->matchedHetznerServer = $matched;
            } else {
                $this->hetznerNoMatchFound = true;
            }
        } catch (\Throwable $e) {
            $this->hetznerSearchError = 'Failed to search Hetzner servers: '.$e->getMessage();
        }
    }

    public function searchHetznerServerById(): void
    {
        $this->hetznerSearchError = null;
        $this->hetznerNoMatchFound = false;
        $this->matchedHetznerServer = null;

        if (! $this->selectedHetznerTokenId) {
            $this->hetznerSearchError = 'Please select a Hetzner token first.';

            return;
        }

        if (! $this->manualHetznerServerId) {
            $this->hetznerSearchError = 'Please enter a Hetzner Server ID.';

            return;
        }

        try {
            $this->authorize('update', $this->server);

            $token = $this->availableHetznerTokens->firstWhere('id', $this->selectedHetznerTokenId);
            if (! $token) {
                $this->hetznerSearchError = 'Invalid token selected.';

                return;
            }

            $hetznerService = new HetznerService($token->token);
            $serverData = $hetznerService->getServer((int) $this->manualHetznerServerId);

            if (! empty($serverData)) {
                $this->matchedHetznerServer = $serverData;
            } else {
                $this->hetznerNoMatchFound = true;
            }
        } catch (\Throwable $e) {
            $this->hetznerSearchError = 'Failed to fetch Hetzner server: '.$e->getMessage();
        }
    }

    public function linkToHetzner()
    {
        if (! $this->matchedHetznerServer) {
            $this->dispatch('error', 'No Hetzner server selected.');

            return;
        }

        try {
            $this->authorize('update', $this->server);

            $token = $this->availableHetznerTokens->firstWhere('id', $this->selectedHetznerTokenId);
            if (! $token) {
                $this->dispatch('error', 'Invalid token selected.');

                return;
            }

            // Verify the server exists and is accessible with the token
            $hetznerService = new HetznerService($token->token);
            $serverData = $hetznerService->getServer($this->matchedHetznerServer['id']);

            if (empty($serverData)) {
                $this->dispatch('error', 'Could not find Hetzner server with ID: '.$this->matchedHetznerServer['id']);

                return;
            }

            // Update the server with Hetzner details
            $this->server->update([
                'cloud_provider_token_id' => $this->selectedHetznerTokenId,
                'hetzner_server_id' => $this->matchedHetznerServer['id'],
                'hetzner_server_status' => $serverData['status'] ?? null,
            ]);

            $this->hetznerServerStatus = $serverData['status'] ?? null;

            // Clear the linking state
            $this->matchedHetznerServer = null;
            $this->selectedHetznerTokenId = null;
            $this->manualHetznerServerId = null;
            $this->hetznerNoMatchFound = false;
            $this->hetznerSearchError = null;

            $this->dispatch('success', 'Server successfully linked to Hetzner Cloud!');
            $this->dispatch('refreshServerShow');
        } catch (\Throwable $e) {
            return handleError($e, $this);
        }
    }

    public function searchDigitalOceanDroplet(): void
    {
        $this->digitalOceanSearchError = null;
        $this->digitalOceanNoMatchFound = false;
        $this->matchedDigitalOceanDroplet = null;

        if (! $this->selectedDigitalOceanTokenId) {
            $this->digitalOceanSearchError = 'Please select a DigitalOcean token.';

            return;
        }

        try {
            $this->authorize('update', $this->server);

            $token = $this->availableDigitalOceanTokens->firstWhere('id', $this->selectedDigitalOceanTokenId);
            if (! $token) {
                $this->digitalOceanSearchError = 'Invalid token selected.';

                return;
            }

            $digitalOceanService = new DigitalOceanService($token->token);
            $matched = $digitalOceanService->findDropletByIp($this->server->ip);

            if ($matched) {
                $this->matchedDigitalOceanDroplet = $matched;
            } else {
                $this->digitalOceanNoMatchFound = true;
            }
        } catch (\Throwable $e) {
            $this->digitalOceanSearchError = 'Failed to search DigitalOcean droplets: '.$e->getMessage();
        }
    }

    public function searchDigitalOceanDropletById(): void
    {
        $this->digitalOceanSearchError = null;
        $this->digitalOceanNoMatchFound = false;
        $this->matchedDigitalOceanDroplet = null;

        if (! $this->selectedDigitalOceanTokenId) {
            $this->digitalOceanSearchError = 'Please select a DigitalOcean token first.';

            return;
        }

        if (! $this->manualDigitalOceanDropletId) {
            $this->digitalOceanSearchError = 'Please enter a DigitalOcean Droplet ID.';

            return;
        }

        try {
            $this->authorize('update', $this->server);

            $token = $this->availableDigitalOceanTokens->firstWhere('id', $this->selectedDigitalOceanTokenId);
            if (! $token) {
                $this->digitalOceanSearchError = 'Invalid token selected.';

                return;
            }

            $digitalOceanService = new DigitalOceanService($token->token);
            $dropletData = $digitalOceanService->getDroplet((int) $this->manualDigitalOceanDropletId);

            if (! empty($dropletData)) {
                $this->matchedDigitalOceanDroplet = $dropletData;
            } else {
                $this->digitalOceanNoMatchFound = true;
            }
        } catch (\Throwable $e) {
            $this->digitalOceanSearchError = 'Failed to fetch DigitalOcean droplet: '.$e->getMessage();
        }
    }

    public function linkToDigitalOcean()
    {
        if (! $this->matchedDigitalOceanDroplet) {
            $this->dispatch('error', 'No DigitalOcean droplet selected.');

            return;
        }

        try {
            $this->authorize('update', $this->server);

            $token = $this->availableDigitalOceanTokens->firstWhere('id', $this->selectedDigitalOceanTokenId);
            if (! $token) {
                $this->dispatch('error', 'Invalid token selected.');

                return;
            }

            $digitalOceanService = new DigitalOceanService($token->token);
            $dropletData = $digitalOceanService->getDroplet((int) $this->matchedDigitalOceanDroplet['id']);

            if (empty($dropletData)) {
                $this->dispatch('error', 'Could not find DigitalOcean droplet with ID: '.$this->matchedDigitalOceanDroplet['id']);

                return;
            }

            $ip = $digitalOceanService->getPublicIpAddress($dropletData);
            $updates = [
                'cloud_provider_token_id' => $this->selectedDigitalOceanTokenId,
                'digitalocean_droplet_id' => $this->matchedDigitalOceanDroplet['id'],
                'digitalocean_droplet_status' => $dropletData['status'] ?? null,
            ];

            if ($ip) {
                $updates['ip'] = $ip;
            }

            $this->server->update($updates);
            $this->digitalOceanDropletStatus = $dropletData['status'] ?? null;

            $this->matchedDigitalOceanDroplet = null;
            $this->selectedDigitalOceanTokenId = null;
            $this->manualDigitalOceanDropletId = null;
            $this->digitalOceanNoMatchFound = false;
            $this->digitalOceanSearchError = null;

            $this->dispatch('success', 'Server successfully linked to DigitalOcean!');
            $this->dispatch('refreshServerShow');
        } catch (\Throwable $e) {
            return handleError($e, $this);
        }
    }

    public function searchVultrInstance(): void
    {
        $this->vultrSearchError = null;
        $this->vultrNoMatchFound = false;
        $this->matchedVultrInstance = null;

        if (! $this->selectedVultrTokenId) {
            $this->vultrSearchError = 'Please select a Vultr token.';

            return;
        }

        try {
            $this->authorize('update', $this->server);

            $token = $this->availableVultrTokens->firstWhere('id', $this->selectedVultrTokenId);
            if (! $token) {
                $this->vultrSearchError = 'Invalid token selected.';

                return;
            }

            $vultrService = new VultrService($token->token);
            $matched = $vultrService->findInstanceByIp($this->server->ip);

            if ($matched) {
                $this->matchedVultrInstance = $matched;
            } else {
                $this->vultrNoMatchFound = true;
            }
        } catch (\Throwable $e) {
            $this->vultrSearchError = 'Failed to search Vultr instances: '.$e->getMessage();
        }
    }

    public function searchVultrInstanceById(): void
    {
        $this->vultrSearchError = null;
        $this->vultrNoMatchFound = false;
        $this->matchedVultrInstance = null;

        if (! $this->selectedVultrTokenId) {
            $this->vultrSearchError = 'Please select a Vultr token first.';

            return;
        }

        if (! $this->manualVultrInstanceId) {
            $this->vultrSearchError = 'Please enter a Vultr Instance ID.';

            return;
        }

        try {
            $this->authorize('update', $this->server);

            $token = $this->availableVultrTokens->firstWhere('id', $this->selectedVultrTokenId);
            if (! $token) {
                $this->vultrSearchError = 'Invalid token selected.';

                return;
            }

            $vultrService = new VultrService($token->token);
            $instanceData = $vultrService->getInstance($this->manualVultrInstanceId);

            if (! empty($instanceData)) {
                $this->matchedVultrInstance = $instanceData;
            } else {
                $this->vultrNoMatchFound = true;
            }
        } catch (\Throwable $e) {
            $this->vultrSearchError = 'Failed to fetch Vultr instance: '.$e->getMessage();
        }
    }

    public function linkToVultr()
    {
        if (! $this->matchedVultrInstance) {
            $this->dispatch('error', 'No Vultr instance selected.');

            return;
        }

        try {
            $this->authorize('update', $this->server);

            $token = $this->availableVultrTokens->firstWhere('id', $this->selectedVultrTokenId);
            if (! $token) {
                $this->dispatch('error', 'Invalid token selected.');

                return;
            }

            $vultrService = new VultrService($token->token);
            $instanceData = $vultrService->getInstance($this->matchedVultrInstance['id']);

            if (empty($instanceData)) {
                $this->dispatch('error', 'Could not find Vultr instance with ID: '.$this->matchedVultrInstance['id']);

                return;
            }

            $this->server->update([
                'cloud_provider_token_id' => $this->selectedVultrTokenId,
                'vultr_instance_id' => $this->matchedVultrInstance['id'],
                'vultr_instance_status' => $instanceData['status'] ?? null,
            ]);

            $this->vultrInstanceStatus = $instanceData['status'] ?? null;

            $this->matchedVultrInstance = null;
            $this->selectedVultrTokenId = null;
            $this->manualVultrInstanceId = null;
            $this->vultrNoMatchFound = false;
            $this->vultrSearchError = null;

            $this->dispatch('success', 'Server successfully linked to Vultr!');
            $this->dispatch('refreshServerShow');
        } catch (\Throwable $e) {
            return handleError($e, $this);
        }
    }

    public function render()
    {
        return view('livewire.server.show');
    }
}
