<?php

declare(strict_types=1);

namespace App\Filament\Resources\BaselineSnapshotResource\Pages;

use App\Filament\Resources\BaselineSnapshotResource;
use App\Models\BaselineSnapshot;
use App\Models\User;
use App\Models\Workspace;
use App\Services\Auth\WorkspaceCapabilityResolver;
use App\Services\Baselines\SnapshotRendering\BaselineSnapshotPresenter;
use App\Support\Auth\Capabilities;
use App\Support\Badges\BadgeDomain;
use App\Support\Badges\BadgeRenderer;
use App\Support\Navigation\CrossResourceNavigationMatrix;
use App\Support\Navigation\RelatedContextEntry;
use App\Support\Navigation\RelatedNavigationResolver;
use Filament\Actions\Action;
use Filament\Infolists\Components\TextEntry;
use Filament\Infolists\Components\ViewEntry;
use Filament\Resources\Pages\ViewRecord;
use Filament\Schemas\Components\Section;
use Filament\Schemas\Schema;

class ViewBaselineSnapshot extends ViewRecord
{
    protected static string $resource = BaselineSnapshotResource::class;

    /**
     * @var array<string, mixed>
     */
    public array $presentedSnapshot = [];

    public function mount(int|string $record): void
    {
        parent::mount($record);

        $snapshot = $this->getRecord();

        if ($snapshot instanceof BaselineSnapshot) {
            $this->presentedSnapshot = app(BaselineSnapshotPresenter::class)
                ->present($snapshot)
                ->toArray();
        }
    }

    protected function authorizeAccess(): void
    {
        $user = auth()->user();
        $snapshot = $this->getRecord();
        $workspace = BaselineSnapshotResource::resolveWorkspace();

        if (! $user instanceof User || ! $snapshot instanceof BaselineSnapshot || ! $workspace instanceof Workspace) {
            abort(404);
        }

        if ((int) $snapshot->workspace_id !== (int) $workspace->getKey()) {
            abort(404);
        }

        /** @var WorkspaceCapabilityResolver $resolver */
        $resolver = app(WorkspaceCapabilityResolver::class);

        if (! $resolver->isMember($user, $workspace)) {
            abort(404);
        }

        if (! $resolver->can($user, $workspace, Capabilities::WORKSPACE_BASELINES_VIEW)) {
            abort(403);
        }
    }

    public function infolist(Schema $schema): Schema
    {
        return $schema
            ->schema([
                Section::make('Snapshot')
                    ->schema([
                        TextEntry::make('snapshot_id')
                            ->label('Snapshot')
                            ->state(function (): string {
                                $snapshotId = data_get($this->presentedSnapshot, 'snapshot.snapshotId');

                                return is_numeric($snapshotId) ? '#'.$snapshotId : '—';
                            }),
                        TextEntry::make('baseline_profile_name')
                            ->label('Baseline')
                            ->state(fn (): string => data_get($this->presentedSnapshot, 'snapshot.baselineProfileName', '—'))
                            ->placeholder('—'),
                        TextEntry::make('captured_at')
                            ->label('Captured')
                            ->state(fn (): ?string => data_get($this->presentedSnapshot, 'snapshot.capturedAt'))
                            ->dateTime()
                            ->placeholder('—'),
                        TextEntry::make('state_label')
                            ->label('State')
                            ->badge()
                            ->state(fn (): string => data_get($this->presentedSnapshot, 'snapshot.stateLabel', 'Complete'))
                            ->color(fn (string $state): string => $state === 'Captured with gaps' ? 'warning' : 'success'),
                        TextEntry::make('overall_fidelity')
                            ->label('Overall fidelity')
                            ->badge()
                            ->state(fn (): ?string => data_get($this->presentedSnapshot, 'snapshot.overallFidelity'))
                            ->formatStateUsing(BadgeRenderer::label(BadgeDomain::BaselineSnapshotFidelity))
                            ->color(BadgeRenderer::color(BadgeDomain::BaselineSnapshotFidelity))
                            ->icon(BadgeRenderer::icon(BadgeDomain::BaselineSnapshotFidelity)),
                        TextEntry::make('fidelity_summary')
                            ->label('Evidence mix')
                            ->state(fn (): string => data_get($this->presentedSnapshot, 'snapshot.fidelitySummary', 'Content 0, Meta 0')),
                        TextEntry::make('overall_gap_count')
                            ->label('Evidence gaps')
                            ->state(fn (): int => (int) data_get($this->presentedSnapshot, 'snapshot.overallGapCount', 0)),
                        TextEntry::make('snapshot_identity_hash')
                            ->label('Identity hash')
                            ->state(fn (): ?string => data_get($this->presentedSnapshot, 'snapshot.snapshotIdentityHash'))
                            ->copyable()
                            ->placeholder('—')
                            ->columnSpanFull(),
                    ])
                    ->columns(2)
                    ->columnSpanFull(),
                Section::make('Coverage summary')
                    ->schema([
                        ViewEntry::make('summary_rows')
                            ->label('')
                            ->view('filament.infolists.entries.baseline-snapshot-summary-table')
                            ->state(fn (): array => data_get($this->presentedSnapshot, 'summaryRows', []))
                            ->columnSpanFull(),
                    ])
                    ->columnSpanFull(),
                Section::make('Related context')
                    ->schema([
                        ViewEntry::make('related_context')
                            ->label('')
                            ->view('filament.infolists.entries.related-context')
                            ->state(fn (): array => app(RelatedNavigationResolver::class)
                                ->detailEntries(CrossResourceNavigationMatrix::SOURCE_BASELINE_SNAPSHOT, $this->getRecord()))
                            ->columnSpanFull(),
                    ])
                    ->columnSpanFull(),
                Section::make('Captured policy types')
                    ->schema([
                        ViewEntry::make('groups')
                            ->label('')
                            ->view('filament.infolists.entries.baseline-snapshot-groups')
                            ->state(fn (): array => data_get($this->presentedSnapshot, 'groups', []))
                            ->columnSpanFull(),
                    ])
                    ->columnSpanFull(),
                Section::make('Technical detail')
                    ->schema([
                        ViewEntry::make('technical_detail')
                            ->label('')
                            ->view('filament.infolists.entries.baseline-snapshot-technical-detail')
                            ->state(fn (): array => data_get($this->presentedSnapshot, 'technicalDetail', []))
                            ->columnSpanFull(),
                    ])
                    ->collapsible()
                    ->collapsed()
                    ->columnSpanFull(),
            ]);
    }

    protected function getHeaderActions(): array
    {
        return [
            Action::make('primary_related')
                ->label(fn (): string => $this->primaryRelatedEntry()?->actionLabel ?? 'Open related record')
                ->url(fn (): ?string => $this->primaryRelatedEntry()?->targetUrl)
                ->hidden(fn (): bool => ! ($this->primaryRelatedEntry()?->isAvailable() ?? false))
                ->color('gray'),
        ];
    }

    private function primaryRelatedEntry(): ?RelatedContextEntry
    {
        return app(RelatedNavigationResolver::class)
            ->headerEntries(CrossResourceNavigationMatrix::SOURCE_BASELINE_SNAPSHOT, $this->getRecord())[0] ?? null;
    }
}
