<?php

declare(strict_types=1);

namespace App\Filament\System\Pages\Ops;

use App\Models\OperationRun;
use App\Models\PlatformUser;
use App\Services\SystemConsole\OperationRunTriageService;
use App\Support\Auth\PlatformCapabilities;
use App\Support\Badges\BadgeDomain;
use App\Support\Badges\BadgeRenderer;
use App\Support\OperationCatalog;
use App\Support\OperationRunOutcome;
use App\Support\OperationRunStatus;
use App\Support\OpsUx\OperationUxPresenter;
use App\Support\System\SystemOperationRunLinks;
use Filament\Actions\Action;
use Filament\Forms\Components\Textarea;
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\Database\Eloquent\Builder;

class Failures extends Page implements HasTable
{
    use InteractsWithTable;

    protected static ?string $navigationLabel = 'Failures';

    protected static string|\BackedEnum|null $navigationIcon = 'heroicon-o-exclamation-triangle';

    protected static string|\UnitEnum|null $navigationGroup = 'Ops';

    protected static ?string $slug = 'ops/failures';

    protected string $view = 'filament.system.pages.ops.failures';

    public static function getNavigationBadge(): ?string
    {
        $count = OperationRun::query()
            ->where('status', OperationRunStatus::Completed->value)
            ->where('outcome', OperationRunOutcome::Failed->value)
            ->count();

        return $count > 0 ? (string) $count : null;
    }

    public static function getNavigationBadgeColor(): string|array|null
    {
        return 'danger';
    }

    public static function canAccess(): bool
    {
        $user = auth('platform')->user();

        if (! $user instanceof PlatformUser) {
            return false;
        }

        return $user->hasCapability(PlatformCapabilities::OPERATIONS_VIEW)
            || ($user->hasCapability(PlatformCapabilities::OPS_VIEW) && $user->hasCapability(PlatformCapabilities::RUNBOOKS_VIEW));
    }

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

    public function table(Table $table): Table
    {
        return $table
            ->defaultSort('id', 'desc')
            ->paginated(\App\Support\Filament\TablePaginationProfiles::customPage())
            ->query(function (): Builder {
                return OperationRun::query()
                    ->with(['tenant', 'workspace'])
                    ->where('status', OperationRunStatus::Completed->value)
                    ->where('outcome', OperationRunOutcome::Failed->value);
            })
            ->columns([
                TextColumn::make('id')
                    ->label('Run')
                    ->state(fn (OperationRun $record): string => '#'.$record->getKey()),
                TextColumn::make('status')
                    ->badge()
                    ->formatStateUsing(BadgeRenderer::label(BadgeDomain::OperationRunStatus))
                    ->color(BadgeRenderer::color(BadgeDomain::OperationRunStatus))
                    ->icon(BadgeRenderer::icon(BadgeDomain::OperationRunStatus))
                    ->iconColor(BadgeRenderer::iconColor(BadgeDomain::OperationRunStatus)),
                TextColumn::make('outcome')
                    ->badge()
                    ->formatStateUsing(BadgeRenderer::label(BadgeDomain::OperationRunOutcome))
                    ->color(BadgeRenderer::color(BadgeDomain::OperationRunOutcome))
                    ->icon(BadgeRenderer::icon(BadgeDomain::OperationRunOutcome))
                    ->iconColor(BadgeRenderer::iconColor(BadgeDomain::OperationRunOutcome)),
                TextColumn::make('type')
                    ->label('Operation')
                    ->formatStateUsing(fn (?string $state): string => OperationCatalog::label((string) $state))
                    ->searchable(),
                TextColumn::make('workspace.name')
                    ->label('Workspace')
                    ->toggleable(),
                TextColumn::make('tenant.name')
                    ->label('Tenant')
                    ->formatStateUsing(fn (?string $state): string => $state ?: 'Tenantless')
                    ->toggleable(),
                TextColumn::make('created_at')->label('Started')->since(),
            ])
            ->recordUrl(fn (OperationRun $record): string => SystemOperationRunLinks::view($record))
            ->actions([
                Action::make('retry')
                    ->label('Retry')
                    ->requiresConfirmation()
                    ->visible(fn (OperationRun $record): bool => $this->canManageOperations() && app(OperationRunTriageService::class)->canRetry($record))
                    ->action(function (OperationRun $record, OperationRunTriageService $triageService): void {
                        $user = $this->requireManageUser();
                        $retryRun = $triageService->retry($record, $user);

                        OperationUxPresenter::queuedToast((string) $retryRun->type)
                            ->actions([
                                \Filament\Actions\Action::make('view_run')
                                    ->label('View run')
                                    ->url(SystemOperationRunLinks::view($retryRun)),
                            ])
                            ->send();
                    }),
                Action::make('cancel')
                    ->label('Cancel')
                    ->color('danger')
                    ->requiresConfirmation()
                    ->visible(fn (OperationRun $record): bool => $this->canManageOperations() && app(OperationRunTriageService::class)->canCancel($record))
                    ->action(function (OperationRun $record, OperationRunTriageService $triageService): void {
                        $user = $this->requireManageUser();
                        $triageService->cancel($record, $user);

                        Notification::make()
                            ->title('Run cancelled')
                            ->success()
                            ->send();
                    }),
                Action::make('mark_investigated')
                    ->label('Mark investigated')
                    ->requiresConfirmation()
                    ->visible(fn (): bool => $this->canManageOperations())
                    ->form([
                        Textarea::make('reason')
                            ->label('Reason')
                            ->required()
                            ->minLength(5)
                            ->maxLength(500)
                            ->rows(4),
                    ])
                    ->action(function (OperationRun $record, array $data, OperationRunTriageService $triageService): void {
                        $user = $this->requireManageUser();
                        $triageService->markInvestigated($record, $user, (string) ($data['reason'] ?? ''));

                        Notification::make()
                            ->title('Run marked as investigated')
                            ->success()
                            ->send();
                    }),
            ])
            ->emptyStateHeading('No failed runs found')
            ->emptyStateDescription('Failed operations will appear here for triage.')
            ->bulkActions([]);
    }

    private function canManageOperations(): bool
    {
        $user = auth('platform')->user();

        return $user instanceof PlatformUser
            && $user->hasCapability(PlatformCapabilities::OPERATIONS_MANAGE);
    }

    private function requireManageUser(): PlatformUser
    {
        $user = auth('platform')->user();

        if (! $user instanceof PlatformUser || ! $user->hasCapability(PlatformCapabilities::OPERATIONS_MANAGE)) {
            abort(403);
        }

        return $user;
    }
}
