<?php

namespace App\Filament\Widgets;

use App\Api\Plugins\PluginLoader;
use App\Filament\Resources\ApiProviders\ApiProviderResource;
use App\Models\ApiProvider;
use Filament\Actions\Action;
use Filament\Actions\BulkAction;
use Filament\Actions\BulkActionGroup;
use Filament\Notifications\Notification;
use Filament\Tables\Columns\TextColumn;
use Filament\Widgets\TableWidget;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use RuntimeException;
use Throwable;

class ApiProviderHealth extends TableWidget
{
    protected static ?string $heading = 'API Provider Health';

    protected static ?string $description = 'Status, Tests & Quick enable';

    protected int|string|array $columnSpan = 'full';

    protected static ?int $sort = -5;

    protected function getTableQuery(): Builder
    {
        return ApiProvider::query()
            ->orderByRaw('enabled = 0 desc')
            ->orderByRaw("case when coalesce(last_status, '') = 'online' then 1 else 0 end")
            ->orderByDesc('updated_at');
    }

    protected function getTableColumns(): array
    {
        return [
            TextColumn::make('name')
                ->label('Provider')
                ->searchable()
                ->sortable()
                ->wrap()
                ->url(fn (ApiProvider $record): string => ApiProviderResource::getUrl('edit', ['record' => $record]))
                ->openUrlInNewTab(),
            TextColumn::make('plugin')
                ->label('Plugin')
                ->badge()
                ->color('gray'),
            TextColumn::make('status_label')
                ->label('Status')
                ->badge()
                ->state(fn (ApiProvider $record): string => $this->statusLabel($record))
                ->color(fn (ApiProvider $record): string => $this->statusColor($record)),
            TextColumn::make('last_response_time_ms')
                ->label('Latency')
                ->formatStateUsing(fn (?int $state): string => $state ? $state.' ms' : '—')
                ->color('gray'),
            TextColumn::make('last_checked_at')
                ->label('Geprüft')
                ->formatStateUsing(fn ($state): string => $state ? $state->diffForHumans() : 'Noch nie')
                ->sortable(),
            TextColumn::make('last_error')
                ->label('Letzter Fehler')
                ->limit(40)
                ->tooltip(fn (ApiProvider $record): ?string => $record->last_error),
        ];
    }

    protected function getTableActions(): array
    {
        return [
            Action::make('test')
                ->label('Testen')
                ->icon('heroicon-o-bolt')
                ->color('warning')
                ->action(function (ApiProvider $record): void {
                    $this->testProvider($record);
                }),
            Action::make('toggle')
                ->label(fn (ApiProvider $record): string => $record->enabled ? 'Deaktivieren' : 'Aktivieren')
                ->icon('heroicon-o-power')
                ->color(fn (ApiProvider $record): string => $record->enabled ? 'gray' : 'success')
                ->requiresConfirmation(fn (ApiProvider $record): bool => $record->enabled)
                ->action(function (ApiProvider $record): void {
                    if ($record->enabled) {
                        $this->disableProvider($record);

                        return;
                    }

                    $this->enableProvider($record, true);
                }),
        ];
    }

    protected function getTableHeaderActions(): array
    {
        return [
            Action::make('refresh')
                ->label('Alle testen')
                ->icon('heroicon-o-arrow-path')
                ->color('gray')
                ->action(function (): void {
                    $this->testAllProviders();
                }),
        ];
    }

    protected function getTableBulkActions(): array
    {
        return [
            BulkActionGroup::make([
                BulkAction::make('bulkEnable')
                    ->label('Aktivieren')
                    ->icon('heroicon-o-power')
                    ->color('success')
                    ->action(function (Collection $records): void {
                        $records->each(function (ApiProvider $record): void {
                            $this->enableProvider($record, false);
                        });
                    }),
                BulkAction::make('bulkDisable')
                    ->label('Deaktivieren')
                    ->icon('heroicon-o-stop')
                    ->color('gray')
                    ->action(function (Collection $records): void {
                        $records->each(function (ApiProvider $record): void {
                            $this->disableProvider($record);
                        });
                    }),
            ]),
        ];
    }

    private function testProvider(ApiProvider $provider): void
    {
        $result = $this->probeProvider($provider);

        $notification = Notification::make()
            ->title($result['ok'] ? 'Verbindung erfolgreich' : 'Verbindung fehlgeschlagen')
            ->body($result['error'] ?? 'Provider antwortet.');

        $result['ok']
            ? $notification->success()
            : $notification->danger();

        $notification->send();
    }

    private function testAllProviders(): void
    {
        ApiProvider::query()->get()->each(fn (ApiProvider $provider) => $this->probeProvider($provider));

        Notification::make()
            ->title('Tests gestartet')
            ->body('Alle Provider wurden geprüft.')
            ->success()
            ->send();
    }

    private function enableProvider(ApiProvider $provider, bool $withTest = true): void
    {
        $ok = true;
        $result = null;

        if ($withTest) {
            $result = $this->probeProvider($provider);
            $ok = $result['ok'];
        }

        if ($ok) {
            $provider->forceFill(['enabled' => true])->save();

            Notification::make()
                ->title('Provider aktiviert')
                ->body($provider->name.' ist aktiviert'.($result ? ' (Test ok).' : '.'))
                ->success()
                ->send();

            return;
        }

        Notification::make()
            ->title('Aktivierung abgebrochen')
            ->body($result['error'] ?? 'Verbindung fehlgeschlagen.')
            ->danger()
            ->send();
    }

    private function disableProvider(ApiProvider $provider): void
    {
        $provider->disableWithDependencies();

        Notification::make()
            ->title('Provider deaktiviert')
            ->body($provider->name.' wurde deaktiviert.')
            ->success()
            ->send();
    }

    private function probeProvider(ApiProvider $provider): array
    {
        $startedAt = microtime(true);
        $status = $provider->enabled ? 'offline' : 'disabled';
        $error = null;
        $duration = null;
        $ok = false;

        try {
            if (! $provider->plugin) {
                $status = 'plugin_missing';
                throw new RuntimeException('Kein Plugin definiert.');
            }

            $plugin = PluginLoader::getPlugin($provider->plugin, $provider);
            $success = $plugin->testConnection($provider->toArray());
            $status = $success ? 'online' : 'offline';
            $ok = $success;
        } catch (Throwable $exception) {
            $status = match (true) {
                $status === 'disabled' => 'disabled',
                $status === 'plugin_missing' => 'plugin_missing',
                default => 'error',
            };
            $error = $exception->getMessage();
        } finally {
            $duration = (int) round((microtime(true) - $startedAt) * 1000);
        }

        $provider->forceFill([
            'last_checked_at' => now(),
            'last_status' => $status,
            'last_response_time_ms' => $duration,
            'last_error' => $error,
        ])->save();

        return [
            'ok' => $ok,
            'error' => $error,
            'duration' => $duration,
        ];
    }

    private function statusLabel(ApiProvider $provider): string
    {
        if (! $provider->enabled) {
            return 'Disabled';
        }

        return match ($provider->last_status) {
            'online' => 'Online',
            'offline' => 'Offline',
            'error' => 'Error',
            'plugin_missing' => 'Plugin fehlt',
            default => 'Unbekannt',
        };
    }

    private function statusColor(ApiProvider $provider): string
    {
        if (! $provider->enabled) {
            return 'gray';
        }

        return match ($provider->last_status) {
            'online' => 'success',
            'offline' => 'danger',
            'error' => 'danger',
            'plugin_missing' => 'warning',
            default => 'warning',
        };
    }
}
