<?php

namespace App\Filament\Resources;

use App\Filament\Resources\OperationRunResource\Pages;
use App\Models\OperationRun;
use App\Models\Tenant;
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\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 getEloquentQuery(): Builder
    {
        $tenantId = Tenant::current()?->getKey();

        return parent::getEloquentQuery()
            ->with('user')
            ->latest('id')
            ->when($tenantId, fn (Builder $query) => $query->where('tenant_id', $tenantId));
    }

    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()
                            ->formatStateUsing(BadgeRenderer::label(BadgeDomain::OperationRunStatus))
                            ->color(BadgeRenderer::color(BadgeDomain::OperationRunStatus))
                            ->icon(BadgeRenderer::icon(BadgeDomain::OperationRunStatus))
                            ->iconColor(BadgeRenderer::iconColor(BadgeDomain::OperationRunStatus)),
                        TextEntry::make('outcome')
                            ->badge()
                            ->formatStateUsing(BadgeRenderer::label(BadgeDomain::OperationRunOutcome))
                            ->color(BadgeRenderer::color(BadgeDomain::OperationRunOutcome))
                            ->icon(BadgeRenderer::icon(BadgeDomain::OperationRunOutcome))
                            ->iconColor(BadgeRenderer::iconColor(BadgeDomain::OperationRunOutcome)),
                        TextEntry::make('initiator_name')->label('Initiator'),
                        TextEntry::make('target_scope_display')
                            ->label('Target')
                            ->getStateUsing(fn (OperationRun $record): ?string => static::targetScopeDisplay($record))
                            ->visible(fn (OperationRun $record): bool => static::targetScopeDisplay($record) !== null)
                            ->columnSpanFull(),
                        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')
            ->columns([
                Tables\Columns\TextColumn::make('status')
                    ->badge()
                    ->formatStateUsing(BadgeRenderer::label(BadgeDomain::OperationRunStatus))
                    ->color(BadgeRenderer::color(BadgeDomain::OperationRunStatus))
                    ->icon(BadgeRenderer::icon(BadgeDomain::OperationRunStatus))
                    ->iconColor(BadgeRenderer::iconColor(BadgeDomain::OperationRunStatus)),
                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()
                    ->formatStateUsing(BadgeRenderer::label(BadgeDomain::OperationRunOutcome))
                    ->color(BadgeRenderer::color(BadgeDomain::OperationRunOutcome))
                    ->icon(BadgeRenderer::icon(BadgeDomain::OperationRunOutcome))
                    ->iconColor(BadgeRenderer::iconColor(BadgeDomain::OperationRunOutcome)),
            ])
            ->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 getPages(): array
    {
        return [
            'index' => Pages\ListOperationRuns::route('/'),
            'view' => Pages\ViewOperationRun::route('/{record}'),
        ];
    }

    private static function targetScopeDisplay(OperationRun $record): ?string
    {
        $context = is_array($record->context) ? $record->context : [];

        $targetScope = $context['target_scope'] ?? null;
        if (! is_array($targetScope)) {
            return null;
        }

        $entraTenantName = $targetScope['entra_tenant_name'] ?? null;
        $entraTenantId = $targetScope['entra_tenant_id'] ?? null;
        $directoryContextId = $targetScope['directory_context_id'] ?? null;

        $entraTenantName = is_string($entraTenantName) ? trim($entraTenantName) : null;
        $entraTenantId = is_string($entraTenantId) ? trim($entraTenantId) : null;

        $directoryContextId = match (true) {
            is_string($directoryContextId) => trim($directoryContextId),
            is_int($directoryContextId) => (string) $directoryContextId,
            default => null,
        };

        $entra = null;

        if ($entraTenantName !== null && $entraTenantName !== '') {
            $entra = $entraTenantId ? "{$entraTenantName} ({$entraTenantId})" : $entraTenantName;
        } elseif ($entraTenantId !== null && $entraTenantId !== '') {
            $entra = $entraTenantId;
        }

        $parts = array_values(array_filter([
            $entra,
            $directoryContextId ? "directory_context_id: {$directoryContextId}" : null,
        ], fn (?string $value): bool => $value !== null && $value !== ''));

        return $parts !== [] ? implode(' · ', $parts) : null;
    }
}
