<?php

declare(strict_types=1);

namespace App\Filament\Admin\Pages;

use App\Models\AuditLog;
use App\Services\Agent\AgentClient;
use BackedEnum;
use Exception;
use Filament\Actions\Action;
use Filament\Actions\Concerns\InteractsWithActions;
use Filament\Actions\Contracts\HasActions;
use Filament\Forms\Concerns\InteractsWithForms;
use Filament\Forms\Contracts\HasForms;
use Filament\Notifications\Notification;
use Filament\Pages\Page;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Concerns\InteractsWithTable;
use Filament\Tables\Contracts\HasTable;
use Filament\Tables\Table;
use Illuminate\Contracts\Support\Htmlable;
use Illuminate\Database\Eloquent\Model;

class Services extends Page implements HasActions, HasForms, HasTable
{
    use InteractsWithActions;
    use InteractsWithForms;
    use InteractsWithTable;

    protected static string|BackedEnum|null $navigationIcon = 'heroicon-o-cog-6-tooth';

    protected static ?int $navigationSort = 10;

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

    protected string $view = 'filament.admin.pages.services';

    public array $services = [];

    public ?string $selectedService = null;

    protected ?AgentClient $agent = null;

    protected array $baseServices = [
        'nginx' => ['name' => 'Nginx', 'description' => 'Web Server', 'icon' => 'globe'],
        'mariadb' => ['name' => 'MariaDB', 'description' => 'Database Server', 'icon' => 'database'],
        'redis-server' => ['name' => 'Redis', 'description' => 'Cache Server', 'icon' => 'bolt'],
        'postfix' => ['name' => 'Postfix', 'description' => 'Mail Transfer Agent', 'icon' => 'envelope'],
        'dovecot' => ['name' => 'Dovecot', 'description' => 'IMAP/POP3 Server', 'icon' => 'inbox'],
        'rspamd' => ['name' => 'Rspamd', 'description' => 'Spam Filter', 'icon' => 'shield'],
        'clamav-daemon' => ['name' => 'ClamAV', 'description' => 'Antivirus Scanner', 'icon' => 'bug'],
        'named' => ['name' => 'BIND9', 'description' => 'DNS Server', 'icon' => 'server'],
        'opendkim' => ['name' => 'OpenDKIM', 'description' => 'DKIM Signing', 'icon' => 'key'],
        'fail2ban' => ['name' => 'Fail2Ban', 'description' => 'Intrusion Prevention', 'icon' => 'lock'],
        'ssh' => ['name' => 'SSH', 'description' => 'Secure Shell', 'icon' => 'terminal'],
        'cron' => ['name' => 'Cron', 'description' => 'Task Scheduler', 'icon' => 'clock'],
    ];

    protected ?array $managedServices = null;

    protected function getManagedServices(): array
    {
        if ($this->managedServices !== null) {
            return $this->managedServices;
        }

        $this->managedServices = [];
        foreach ($this->baseServices as $key => $config) {
            $this->managedServices[$key] = $config;

            if ($key === 'nginx') {
                foreach ($this->detectPhpFpmVersions() as $service => $phpConfig) {
                    $this->managedServices[$service] = $phpConfig;
                }
            }
        }

        return $this->managedServices;
    }

    protected function detectPhpFpmVersions(): array
    {
        $phpServices = [];
        $output = [];
        exec('ls /lib/systemd/system/php*-fpm.service 2>/dev/null', $output);

        foreach ($output as $servicePath) {
            if (preg_match('/php([\d.]+)-fpm\.service$/', $servicePath, $matches)) {
                $version = $matches[1];
                $serviceName = "php{$version}-fpm";
                $phpServices[$serviceName] = [
                    'name' => "PHP {$version} FPM",
                    'description' => 'PHP FastCGI Process Manager',
                    'icon' => 'code',
                ];
            }
        }

        uksort($phpServices, function ($a, $b) {
            preg_match('/php([\d.]+)-fpm/', $a, $matchA);
            preg_match('/php([\d.]+)-fpm/', $b, $matchB);

            return version_compare($matchB[1] ?? '0', $matchA[1] ?? '0');
        });

        return $phpServices;
    }

    public function getTitle(): string|Htmlable
    {
        return __('Service Manager');
    }

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

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

    public function loadServices(): void
    {
        $managedServices = $this->getManagedServices();

        try {
            $result = $this->getAgent()->send('service.list', [
                'services' => array_keys($managedServices),
            ]);

            if ($result['success'] ?? false) {
                $this->services = [];
                foreach ($result['services'] ?? [] as $name => $status) {
                    $config = $managedServices[$name] ?? [
                        'name' => ucfirst($name),
                        'description' => '',
                        'icon' => 'cog',
                    ];
                    $this->services[$name] = array_merge($config, [
                        'service' => $name,
                        'is_active' => $status['is_active'] ?? false,
                        'is_enabled' => $status['is_enabled'] ?? false,
                        'status' => $status['status'] ?? 'unknown',
                    ]);
                }
            }
        } catch (Exception $e) {
            Notification::make()->title(__('Error loading services'))->body($e->getMessage())->danger()->send();
        }
    }

    public function table(Table $table): Table
    {
        return $table
            ->records(fn () => array_values($this->services))
            ->columns([
                TextColumn::make('name')
                    ->label(__('Service'))
                    ->icon(fn (array $record): string => match ($record['icon'] ?? 'cog') {
                        'globe' => 'heroicon-o-globe-alt',
                        'code' => 'heroicon-o-code-bracket',
                        'database' => 'heroicon-o-circle-stack',
                        'bolt' => 'heroicon-o-bolt',
                        'envelope' => 'heroicon-o-envelope',
                        'inbox' => 'heroicon-o-inbox',
                        'shield' => 'heroicon-o-shield-check',
                        'server' => 'heroicon-o-server',
                        'key' => 'heroicon-o-key',
                        'lock' => 'heroicon-o-lock-closed',
                        'terminal' => 'heroicon-o-command-line',
                        'clock' => 'heroicon-o-clock',
                        'bug' => 'heroicon-o-bug-ant',
                        default => 'heroicon-o-cog-6-tooth',
                    })
                    ->iconColor(fn (array $record): string => $record['is_active'] ? 'success' : 'danger')
                    ->description(fn (array $record): string => $record['description'] ?? '')
                    ->weight('medium')
                    ->searchable(),
                TextColumn::make('is_active')
                    ->label(__('Status'))
                    ->badge()
                    ->formatStateUsing(fn (array $record): string => $record['is_active'] ? __('Running') : __('Stopped'))
                    ->color(fn (array $record): string => $record['is_active'] ? 'success' : 'danger'),
                TextColumn::make('is_enabled')
                    ->label(__('Boot'))
                    ->badge()
                    ->formatStateUsing(fn (array $record): string => $record['is_enabled'] ? __('Enabled') : __('Disabled'))
                    ->color(fn (array $record): string => $record['is_enabled'] ? 'success' : 'warning'),
            ])
            ->recordActions([
                Action::make('start')
                    ->label(__('Start'))
                    ->icon('heroicon-o-play')
                    ->color('success')
                    ->size('sm')
                    ->visible(fn (array $record): bool => ! $record['is_active'])
                    ->action(fn (array $record) => $this->executeServiceAction($record['service'], 'start')),
                Action::make('stop')
                    ->label(__('Stop'))
                    ->icon('heroicon-o-stop')
                    ->color('danger')
                    ->size('sm')
                    ->visible(fn (array $record): bool => $record['is_active'])
                    ->requiresConfirmation()
                    ->modalHeading(__('Stop Service'))
                    ->modalDescription(fn (array $record): string => __('Are you sure you want to stop :service? This may affect running websites and services.', ['service' => $record['name']]))
                    ->modalSubmitActionLabel(__('Stop Service'))
                    ->action(fn (array $record) => $this->executeServiceAction($record['service'], 'stop')),
                Action::make('restart')
                    ->label(fn (array $record): string => $this->shouldReloadService($record['service']) ? __('Reload') : __('Restart'))
                    ->icon('heroicon-o-arrow-path')
                    ->color('info')
                    ->size('sm')
                    ->visible(fn (array $record): bool => $record['is_active'])
                    ->action(fn (array $record) => $this->executeServiceAction(
                        $record['service'],
                        $this->shouldReloadService($record['service']) ? 'reload' : 'restart'
                    )),
                Action::make('enable')
                    ->label(__('Enable'))
                    ->icon('heroicon-o-check')
                    ->color('gray')
                    ->size('sm')
                    ->visible(fn (array $record): bool => ! $record['is_enabled'])
                    ->action(fn (array $record) => $this->executeServiceAction($record['service'], 'enable')),
                Action::make('disable')
                    ->label(__('Disable'))
                    ->icon('heroicon-o-x-mark')
                    ->color('warning')
                    ->size('sm')
                    ->visible(fn (array $record): bool => $record['is_enabled'])
                    ->requiresConfirmation()
                    ->modalHeading(__('Disable Service'))
                    ->modalDescription(fn (array $record): string => __("Are you sure you want to disable :service? It won't start automatically on boot.", ['service' => $record['name']]))
                    ->modalSubmitActionLabel(__('Disable Service'))
                    ->action(fn (array $record) => $this->executeServiceAction($record['service'], 'disable')),
            ])
            ->headerActions([
                Action::make('refresh')
                    ->label(__('Refresh'))
                    ->icon('heroicon-o-arrow-path')
                    ->color('gray')
                    ->action(function () {
                        $this->loadServices();
                        $this->resetTable();
                        Notification::make()->title(__('Services refreshed'))->success()->duration(1500)->send();
                    }),
            ])
            ->emptyStateHeading(__('No services found'))
            ->emptyStateDescription(__('Unable to load system services'))
            ->emptyStateIcon('heroicon-o-cog-6-tooth')
            ->striped();
    }

    public function getTableRecordKey(Model|array $record): string
    {
        return is_array($record) ? $record['service'] : $record->getKey();
    }

    protected function executeServiceAction(string $service, string $action): void
    {
        try {
            $result = $this->getAgent()->send("service.{$action}", [
                'service' => $service,
            ]);

            if ($result['success'] ?? false) {
                $notificationTitle = match ($action) {
                    'start' => __(':service started', ['service' => ucfirst($service)]),
                    'stop' => __(':service stopped', ['service' => ucfirst($service)]),
                    'restart' => __(':service restarted', ['service' => ucfirst($service)]),
                    'reload' => __(':service reloaded', ['service' => ucfirst($service)]),
                    'enable' => __(':service enabled', ['service' => ucfirst($service)]),
                    'disable' => __(':service disabled', ['service' => ucfirst($service)]),
                    default => ucfirst($service).' '.$action
                };

                $actionPast = match ($action) {
                    'start' => 'started',
                    'stop' => 'stopped',
                    'restart' => 'restarted',
                    'reload' => 'reloaded',
                    'enable' => 'enabled',
                    'disable' => 'disabled',
                    default => $action
                };

                Notification::make()
                    ->title($notificationTitle)
                    ->success()
                    ->send();

                AuditLog::logServiceAction($actionPast, $service);

                $this->loadServices();
                $this->resetTable();
            } else {
                throw new Exception($result['error'] ?? $result['message'] ?? __('Unknown error'));
            }
        } catch (Exception $e) {
            Notification::make()
                ->title(__('Action failed'))
                ->body($e->getMessage())
                ->danger()
                ->send();
        }
    }

    protected function getHeaderActions(): array
    {
        return [
        ];
    }

    protected function shouldReloadService(string $service): bool
    {
        if ($service === 'nginx') {
            return true;
        }

        return preg_match('/^php(\d+\.\d+)?-fpm$/', $service) === 1;
    }
}
