<?php

namespace App\Filament\Resources;

use App\Filament\Resources\OperationRunResource\Pages;
use App\Models\OperationRun;
use App\Models\Tenant;
use App\Support\OperationCatalog;
use App\Support\OperationRunOutcome;
use App\Support\OperationRunStatus;
use App\Support\OpsUx\RunDetailPolling;
use App\Support\OpsUx\RunDurationInsights;
use BackedEnum;
use Filament\Actions;
use Filament\Forms\Components\DatePicker;
use Filament\Infolists\Components\TextEntry;
use Filament\Infolists\Components\ViewEntry;
use Filament\Resources\Resource;
use Filament\Schemas\Components\Section;
use Filament\Schemas\Schema;
use Filament\Tables;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use UnitEnum;

class OperationRunResource extends Resource
{
    protected static bool $isScopedToTenant = false;

    protected static ?string $model = OperationRun::class;

    protected static ?string $slug = 'operations';

    protected static string|BackedEnum|null $navigationIcon = 'heroicon-o-queue-list';

    protected static string|UnitEnum|null $navigationGroup = 'Monitoring';

    protected static ?string $navigationLabel = 'Operations';

    public static function form(Schema $schema): Schema
    {
        return $schema;
    }

    public static function infolist(Schema $schema): Schema
    {
        return $schema
            ->schema([
                Section::make('Run')
                    ->schema([
                        TextEntry::make('type')
                            ->badge()
                            ->formatStateUsing(fn (?string $state): string => OperationCatalog::label((string) $state)),
                        TextEntry::make('status')
                            ->badge()
                            ->color(fn (OperationRun $record): string => static::statusColor($record->status)),
                        TextEntry::make('outcome')
                            ->badge()
                            ->color(fn (OperationRun $record): string => static::outcomeColor($record->outcome)),
                        TextEntry::make('initiator_name')->label('Initiator'),
                        TextEntry::make('elapsed')
                            ->label('Elapsed')
                            ->getStateUsing(fn (OperationRun $record): string => RunDurationInsights::elapsedHuman($record)),
                        TextEntry::make('expected_duration')
                            ->label('Expected')
                            ->getStateUsing(fn (OperationRun $record): string => RunDurationInsights::expectedHuman($record) ?? '—'),
                        TextEntry::make('stuck_guidance')
                            ->label('')
                            ->getStateUsing(fn (OperationRun $record): ?string => RunDurationInsights::stuckGuidance($record))
                            ->visible(fn (OperationRun $record): bool => RunDurationInsights::stuckGuidance($record) !== null),
                        TextEntry::make('created_at')->dateTime(),
                        TextEntry::make('started_at')->dateTime()->placeholder('—'),
                        TextEntry::make('completed_at')->dateTime()->placeholder('—'),
                        TextEntry::make('run_identity_hash')->label('Identity hash')->copyable(),
                    ])
                    ->extraAttributes([
                        'x-init' => '$wire.set(\'opsUxIsTabHidden\', document.hidden)',
                        'x-on:visibilitychange.window' => '$wire.set(\'opsUxIsTabHidden\', document.hidden)',
                    ])
                    ->poll(function (OperationRun $record, $livewire): ?string {
                        if (($livewire->opsUxIsTabHidden ?? false) === true) {
                            return null;
                        }

                        if (filled($livewire->mountedActions ?? null)) {
                            return null;
                        }

                        return RunDetailPolling::interval($record);
                    })
                    ->columns(2)
                    ->columnSpanFull(),

                Section::make('Counts')
                    ->schema([
                        ViewEntry::make('summary_counts')
                            ->label('')
                            ->view('filament.infolists.entries.snapshot-json')
                            ->state(fn (OperationRun $record): array => $record->summary_counts ?? [])
                            ->columnSpanFull(),
                    ])
                    ->visible(fn (OperationRun $record): bool => ! empty($record->summary_counts))
                    ->columnSpanFull(),

                Section::make('Failures')
                    ->schema([
                        ViewEntry::make('failure_summary')
                            ->label('')
                            ->view('filament.infolists.entries.snapshot-json')
                            ->state(fn (OperationRun $record): array => $record->failure_summary ?? [])
                            ->columnSpanFull(),
                    ])
                    ->visible(fn (OperationRun $record): bool => ! empty($record->failure_summary))
                    ->columnSpanFull(),

                Section::make('Context')
                    ->schema([
                        ViewEntry::make('context')
                            ->label('')
                            ->view('filament.infolists.entries.snapshot-json')
                            ->state(fn (OperationRun $record): array => $record->context ?? [])
                            ->columnSpanFull(),
                    ])
                    ->columnSpanFull(),
            ]);
    }

    public static function table(Table $table): Table
    {
        return $table
            ->defaultSort('created_at', 'desc')
            ->modifyQueryUsing(function (Builder $query): Builder {
                $tenantId = Tenant::current()?->getKey();

                return $query->when($tenantId, fn (Builder $q) => $q->where('tenant_id', $tenantId));
            })
            ->columns([
                Tables\Columns\TextColumn::make('status')
                    ->badge()
                    ->color(fn (OperationRun $record): string => static::statusColor($record->status)),
                Tables\Columns\TextColumn::make('type')
                    ->label('Operation')
                    ->formatStateUsing(fn (?string $state): string => OperationCatalog::label((string) $state))
                    ->searchable()
                    ->sortable(),
                Tables\Columns\TextColumn::make('initiator_name')
                    ->label('Initiator')
                    ->searchable(),
                Tables\Columns\TextColumn::make('created_at')
                    ->label('Started')
                    ->since()
                    ->sortable(),
                Tables\Columns\TextColumn::make('duration')
                    ->getStateUsing(function (OperationRun $record): string {
                        if ($record->started_at && $record->completed_at) {
                            return $record->completed_at->diffForHumans($record->started_at, true);
                        }

                        return '—';
                    }),
                Tables\Columns\TextColumn::make('outcome')
                    ->badge()
                    ->color(fn (OperationRun $record): string => static::outcomeColor($record->outcome)),
            ])
            ->filters([
                Tables\Filters\SelectFilter::make('type')
                    ->options(function (): array {
                        $tenantId = Tenant::current()?->getKey();

                        if (! $tenantId) {
                            return [];
                        }

                        return OperationRun::query()
                            ->where('tenant_id', $tenantId)
                            ->select('type')
                            ->distinct()
                            ->orderBy('type')
                            ->pluck('type', 'type')
                            ->all();
                    }),
                Tables\Filters\SelectFilter::make('status')
                    ->options([
                        OperationRunStatus::Queued->value => 'Queued',
                        OperationRunStatus::Running->value => 'Running',
                        OperationRunStatus::Completed->value => 'Completed',
                    ]),
                Tables\Filters\SelectFilter::make('outcome')
                    ->options(OperationRunOutcome::uiLabels(includeReserved: false)),
                Tables\Filters\SelectFilter::make('initiator_name')
                    ->label('Initiator')
                    ->options(function (): array {
                        $tenantId = Tenant::current()?->getKey();

                        if (! $tenantId) {
                            return [];
                        }

                        return OperationRun::query()
                            ->where('tenant_id', $tenantId)
                            ->whereNotNull('initiator_name')
                            ->select('initiator_name')
                            ->distinct()
                            ->orderBy('initiator_name')
                            ->pluck('initiator_name', 'initiator_name')
                            ->all();
                    })
                    ->searchable(),
                Tables\Filters\Filter::make('created_at')
                    ->label('Created')
                    ->form([
                        DatePicker::make('created_from')
                            ->label('From'),
                        DatePicker::make('created_until')
                            ->label('Until'),
                    ])
                    ->default(fn (): array => [
                        'created_from' => now()->subDays(30),
                        'created_until' => now(),
                    ])
                    ->query(function (Builder $query, array $data): Builder {
                        $from = $data['created_from'] ?? null;
                        if ($from) {
                            $query->whereDate('created_at', '>=', $from);
                        }

                        $until = $data['created_until'] ?? null;
                        if ($until) {
                            $query->whereDate('created_at', '<=', $until);
                        }

                        return $query;
                    }),
            ])
            ->actions([
                Actions\ViewAction::make(),
            ])
            ->bulkActions([]);
    }

    public static function getEloquentQuery(): Builder
    {
        return parent::getEloquentQuery()
            ->with('user')
            ->latest('id');
    }

    public static function getPages(): array
    {
        return [
            'index' => Pages\ListOperationRuns::route('/'),
            'view' => Pages\ViewOperationRun::route('/{record}'),
        ];
    }

    private static function statusColor(?string $status): string
    {
        return match ($status) {
            'queued' => 'warning',
            'running' => 'info',
            'completed' => 'secondary',
            default => 'gray',
        };
    }

    private static function outcomeColor(?string $outcome): string
    {
        return match ($outcome) {
            'succeeded' => 'success',
            'partially_succeeded' => 'warning',
            'failed' => 'danger',
            'cancelled' => 'gray',
            default => 'gray',
        };
    }
}
