<?php

declare(strict_types=1);

namespace App\Filament\Admin\Pages;

use App\Services\Agent\AgentClient;
use BackedEnum;
use Filament\Actions\Action;
use Filament\Actions\Concerns\InteractsWithActions;
use Filament\Actions\Contracts\HasActions;
use Filament\Notifications\Notification;
use Filament\Pages\Page;
use Filament\Support\Icons\Heroicon;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Concerns\InteractsWithTable;
use Filament\Tables\Contracts\HasTable;
use Filament\Tables\Table;
use Illuminate\Contracts\Support\Htmlable;

class ServerUpdates extends Page implements HasActions, HasTable
{
    use InteractsWithActions;
    use InteractsWithTable;

    protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedArrowPathRoundedSquare;

    protected static ?int $navigationSort = 16;

    protected static ?string $slug = 'server-updates';

    protected string $view = 'filament.admin.pages.server-updates';

    public array $packages = [];

    protected ?AgentClient $agent = null;

    protected bool $updatesLoaded = false;

    public function getTitle(): string|Htmlable
    {
        return __('Server Updates');
    }

    public static function getNavigationLabel(): string
    {
        return __('Server Updates');
    }

    public function mount(): void
    {
        $this->loadUpdates(false);
    }

    protected function getAgent(): AgentClient
    {
        return $this->agent ??= new AgentClient;
    }

    public function loadUpdates(bool $refreshTable = true): void
    {
        try {
            $result = $this->getAgent()->updatesList();
            $this->packages = $result['packages'] ?? [];
            $this->updatesLoaded = true;
        } catch (\Exception $e) {
            $this->packages = [];
            $this->updatesLoaded = true;
            Notification::make()
                ->title(__('Failed to load updates'))
                ->body($e->getMessage())
                ->danger()
                ->send();
        }

        if ($refreshTable) {
            $this->resetTable();
        }
    }

    public function runUpdates(): void
    {
        try {
            $this->getAgent()->updatesRun();
            Notification::make()
                ->title(__('Updates completed'))
                ->success()
                ->send();
        } catch (\Exception $e) {
            Notification::make()
                ->title(__('Update failed'))
                ->body($e->getMessage())
                ->danger()
                ->send();
        }

        $this->loadUpdates();
    }

    public function table(Table $table): Table
    {
        return $table
            ->records(function () {
                if (! $this->updatesLoaded) {
                    $this->loadUpdates(false);
                }

                return collect($this->packages)
                    ->mapWithKeys(function (array $package, int $index): array {
                        $keyParts = [
                            $package['name'] ?? (string) $index,
                            $package['current_version'] ?? '',
                            $package['new_version'] ?? '',
                        ];
                        $key = implode('|', array_filter($keyParts, fn (string $part): bool => $part !== ''));

                        return [$key !== '' ? $key : (string) $index => $package];
                    })
                    ->all();
            })
            ->columns([
                TextColumn::make('name')
                    ->label(__('Package'))
                    ->searchable(),
                TextColumn::make('current_version')
                    ->label(__('Current Version')),
                TextColumn::make('new_version')
                    ->label(__('New Version')),
            ])
            ->emptyStateHeading(__('No updates available'))
            ->emptyStateDescription(__('Your system packages are up to date.'))
            ->headerActions([
                Action::make('refresh')
                    ->label(__('Refresh'))
                    ->icon('heroicon-o-arrow-path')
                    ->action(fn () => $this->loadUpdates()),
                Action::make('runUpdates')
                    ->label(__('Run Updates'))
                    ->icon('heroicon-o-arrow-path-rounded-square')
                    ->color('primary')
                    ->requiresConfirmation()
                    ->modalHeading(__('Install updates'))
                    ->modalDescription(__('This will run apt-get upgrade on the server. Continue?'))
                    ->action(fn () => $this->runUpdates()),
            ]);
    }
}
