<?php

declare(strict_types=1);

namespace App\Filament\Resources;

use App\Filament\Concerns\CleansAdminTenantResourceQueryParameter;
use App\Filament\Resources\BaselineSnapshotResource\Pages;
use App\Models\BaselineProfile;
use App\Models\BaselineSnapshot;
use App\Models\User;
use App\Models\Workspace;
use App\Services\Baselines\BaselineSnapshotTruthResolver;
use App\Services\Baselines\SnapshotRendering\FidelityState;
use App\Support\Auth\Capabilities;
use App\Support\Badges\BadgeCatalog;
use App\Support\Badges\BadgeDomain;
use App\Support\Baselines\BaselineSnapshotLifecycleState;
use App\Support\Filament\FilterPresets;
use App\Support\Navigation\CrossResourceNavigationMatrix;
use App\Support\Navigation\NavigationScope;
use App\Support\Navigation\RelatedContextEntry;
use App\Support\Navigation\RelatedNavigationResolver;
use App\Support\Ui\ActionSurface\ActionSurfaceDeclaration;
use App\Support\Ui\ActionSurface\Enums\ActionSurfaceInspectAffordance;
use App\Support\Ui\ActionSurface\Enums\ActionSurfaceProfile;
use App\Support\Ui\ActionSurface\Enums\ActionSurfaceSlot;
use App\Support\Ui\ActionSurface\Enums\ActionSurfaceType;
use App\Support\Ui\GovernanceArtifactTruth\ArtifactTruthEnvelope;
use App\Support\Ui\GovernanceArtifactTruth\ArtifactTruthPresenter;
use App\Support\Ui\GovernanceArtifactTruth\CompressedGovernanceOutcome;
use App\Support\Ui\GovernanceArtifactTruth\SurfaceCompressionContext;
use App\Support\Workspaces\WorkspaceContext;
use BackedEnum;
use Filament\Actions\Action;
use Filament\Facades\Filament;
use Filament\Resources\Resource;
use Filament\Schemas\Schema;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Filters\SelectFilter;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use UnitEnum;

class BaselineSnapshotResource extends Resource
{
    use CleansAdminTenantResourceQueryParameter;

    protected static bool $isDiscovered = false;

    protected static bool $isScopedToTenant = false;

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

    protected static ?string $slug = 'baseline-snapshots';

    protected static bool $isGloballySearchable = false;

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

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

    protected static ?string $navigationLabel = 'Baseline Snapshots';

    protected static ?int $navigationSort = 2;

    public static function shouldRegisterNavigation(): bool
    {
        if (Filament::getCurrentPanel()?->getId() !== 'admin') {
            return false;
        }

        return NavigationScope::shouldRegisterEnvironmentNavigation()
            && parent::shouldRegisterNavigation();
    }

    public static function canViewAny(): bool
    {
        $user = auth()->user();

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

        $workspace = self::resolveWorkspace();

        if (! $workspace instanceof Workspace) {
            return false;
        }

        $resolver = app(\App\Services\Auth\WorkspaceCapabilityResolver::class);

        return $resolver->isMember($user, $workspace)
            && $resolver->can($user, $workspace, Capabilities::WORKSPACE_BASELINES_VIEW);
    }

    public static function canCreate(): bool
    {
        return false;
    }

    public static function canEdit(Model $record): bool
    {
        return false;
    }

    public static function canDelete(Model $record): bool
    {
        return false;
    }

    public static function canView(Model $record): bool
    {
        if (! $record instanceof BaselineSnapshot) {
            return false;
        }

        $workspace = self::resolveWorkspace();

        if (! $workspace instanceof Workspace) {
            return false;
        }

        return self::canViewAny()
            && (int) $record->workspace_id === (int) $workspace->getKey();
    }

    public static function actionSurfaceDeclaration(): ActionSurfaceDeclaration
    {
        return ActionSurfaceDeclaration::forResource(ActionSurfaceProfile::CrudListAndView, ActionSurfaceType::ReadOnlyRegistryReport)
            ->exempt(ActionSurfaceSlot::ListHeader, 'Snapshots are created by capture runs; no list-header actions.')
            ->satisfy(ActionSurfaceSlot::InspectAffordance, ActionSurfaceInspectAffordance::ClickableRow->value)
            ->exempt(ActionSurfaceSlot::ListRowMoreMenu, 'Snapshots are immutable; rows navigate directly to the detail page.')
            ->exempt(ActionSurfaceSlot::ListBulkMoreGroup, 'Snapshots are immutable; no bulk actions.')
            ->exempt(ActionSurfaceSlot::ListEmptyState, 'Empty-state CTA is intentionally omitted; snapshots appear after baseline captures.')
            ->satisfy(ActionSurfaceSlot::DetailHeader, 'Primary related navigation is surfaced in the view header.');
    }

    public static function getEloquentQuery(): Builder
    {
        $workspaceId = app(WorkspaceContext::class)->currentWorkspaceId(request());

        return parent::getEloquentQuery()
            ->with('baselineProfile')
            ->when(
                $workspaceId !== null,
                fn (Builder $query): Builder => $query->where('workspace_id', (int) $workspaceId),
            )
            ->when(
                $workspaceId === null,
                fn (Builder $query): Builder => $query->whereRaw('1 = 0'),
            );
    }

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

    public static function table(Table $table): Table
    {
        return $table
            ->defaultSort('captured_at', 'desc')
            ->paginated(\App\Support\Filament\TablePaginationProfiles::resource())
            ->persistFiltersInSession()
            ->persistSearchInSession()
            ->persistSortInSession()
            ->columns([
                TextColumn::make('id')
                    ->label('Snapshot')
                    ->formatStateUsing(static fn (?int $state): string => $state ? '#'.$state : '—')
                    ->sortable(),
                TextColumn::make('baselineProfile.name')
                    ->label('Baseline')
                    ->wrap()
                    ->searchable()
                    ->placeholder('—'),
                TextColumn::make('captured_at')
                    ->label('Captured')
                    ->since()
                    ->sortable(),
                TextColumn::make('outcome')
                    ->label('Outcome')
                    ->badge()
                    ->getStateUsing(static fn (BaselineSnapshot $record): string => self::compressedOutcome($record)->primaryLabel)
                    ->color(static fn (BaselineSnapshot $record): string => self::compressedOutcome($record)->primaryBadge->color)
                    ->icon(static fn (BaselineSnapshot $record): ?string => self::compressedOutcome($record)->primaryBadge->icon)
                    ->iconColor(static fn (BaselineSnapshot $record): ?string => self::compressedOutcome($record)->primaryBadge->iconColor)
                    ->description(static fn (BaselineSnapshot $record): ?string => self::truthHeadline($record))
                    ->wrap(),
                TextColumn::make('coverage_summary')
                    ->label('Coverage')
                    ->getStateUsing(static fn (BaselineSnapshot $record): string => self::fidelitySummary($record))
                    ->wrap(),
                TextColumn::make('next_step')
                    ->label('Next step')
                    ->getStateUsing(static fn (BaselineSnapshot $record): string => self::compressedOutcome($record)->nextActionText)
                    ->wrap(),
            ])
            ->recordUrl(static fn (BaselineSnapshot $record): ?string => static::canView($record)
                ? static::getUrl('view', ['record' => $record])
                : null)
            ->filters([
                SelectFilter::make('baseline_profile_id')
                    ->label('Baseline')
                    ->options(static::baselineProfileOptions())
                    ->searchable(),
                SelectFilter::make('lifecycle_state')
                    ->label('Lifecycle')
                    ->options(static::lifecycleOptions())
                    ->query(fn (Builder $query, array $data): Builder => static::applyLifecycleFilter($query, $data['value'] ?? null)),
                FilterPresets::dateRange('captured_at', 'Captured', 'captured_at'),
            ])
            ->actions([
                static::primaryRelatedAction(),
            ])
            ->bulkActions([])
            ->emptyStateHeading('No baseline snapshots')
            ->emptyStateDescription('Capture a baseline snapshot to review evidence fidelity and compare tenants over time.')
            ->emptyStateIcon('heroicon-o-camera');
    }

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

    private static function primaryRelatedAction(): Action
    {
        return Action::make('primary_drill_down')
            ->label(fn (BaselineSnapshot $record): string => static::primaryRelatedEntry($record)?->actionLabel ?? 'Open related record')
            ->url(fn (BaselineSnapshot $record): ?string => static::primaryRelatedEntry($record)?->targetUrl)
            ->hidden(fn (BaselineSnapshot $record): bool => ! (static::primaryRelatedEntry($record)?->isAvailable() ?? false))
            ->color('gray');
    }

    private static function primaryRelatedEntry(BaselineSnapshot $record): ?RelatedContextEntry
    {
        return app(RelatedNavigationResolver::class)
            ->primaryListAction(CrossResourceNavigationMatrix::SOURCE_BASELINE_SNAPSHOT, $record);
    }

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

    /**
     * @return array<int, string>
     */
    private static function baselineProfileOptions(): array
    {
        $workspaceId = app(WorkspaceContext::class)->currentWorkspaceId(request());

        if ($workspaceId === null) {
            return [];
        }

        return BaselineProfile::query()
            ->where('workspace_id', (int) $workspaceId)
            ->orderBy('name')
            ->pluck('name', 'id')
            ->all();
    }

    /**
     * @return array<string, string>
     */
    private static function lifecycleOptions(): array
    {
        return BadgeCatalog::options(BadgeDomain::BaselineSnapshotLifecycle, BaselineSnapshotLifecycleState::values());
    }

    public static function resolveWorkspace(): ?Workspace
    {
        $workspaceId = app(WorkspaceContext::class)->currentWorkspaceId(request());

        if ($workspaceId === null) {
            return null;
        }

        return Workspace::query()->whereKey($workspaceId)->first();
    }

    private static function summary(BaselineSnapshot $snapshot): array
    {
        return is_array($snapshot->summary_jsonb) ? $snapshot->summary_jsonb : [];
    }

    private static function fidelityCounts(BaselineSnapshot $snapshot): array
    {
        $summary = self::summary($snapshot);
        $counts = $summary['fidelity_counts'] ?? null;
        $counts = is_array($counts) ? $counts : [];

        $content = $counts['content'] ?? 0;
        $meta = $counts['meta'] ?? 0;

        return [
            'content' => is_numeric($content) ? (int) $content : 0,
            'meta' => is_numeric($meta) ? (int) $meta : 0,
        ];
    }

    private static function fidelitySummary(BaselineSnapshot $snapshot): string
    {
        $counts = self::fidelityCounts($snapshot);

        return sprintf(
            '%s %d, %s %d',
            BadgeCatalog::spec(BadgeDomain::BaselineSnapshotFidelity, FidelityState::Full->value)->label,
            (int) ($counts['content'] ?? 0),
            BadgeCatalog::spec(BadgeDomain::BaselineSnapshotFidelity, FidelityState::ReferenceOnly->value)->label,
            (int) ($counts['meta'] ?? 0),
        );
    }

    private static function gapsCount(BaselineSnapshot $snapshot): int
    {
        $summary = self::summary($snapshot);
        $gaps = $summary['gaps'] ?? null;
        $gaps = is_array($gaps) ? $gaps : [];
        $byReason = is_array($gaps['by_reason'] ?? null) ? $gaps['by_reason'] : [];

        if ($byReason !== []) {
            return array_sum(array_map(
                static fn (mixed $count, string $reason): int => in_array($reason, ['meta_fallback'], true) || ! is_numeric($count)
                    ? 0
                    : (int) $count,
                $byReason,
                array_keys($byReason),
            ));
        }

        $count = $gaps['count'] ?? 0;

        return is_numeric($count) ? (int) $count : 0;
    }

    private static function hasGaps(BaselineSnapshot $snapshot): bool
    {
        return self::gapsCount($snapshot) > 0;
    }

    private static function lifecycleSpec(BaselineSnapshot $snapshot): \App\Support\Badges\BadgeSpec
    {
        return BadgeCatalog::spec(BadgeDomain::BaselineSnapshotLifecycle, $snapshot->lifecycleState()->value);
    }

    private static function applyLifecycleFilter(Builder $query, mixed $value): Builder
    {
        if (! is_string($value) || trim($value) === '') {
            return $query;
        }

        return $query->where('lifecycle_state', trim($value));
    }

    private static function gapCountExpression(Builder $query): string
    {
        return match ($query->getConnection()->getDriverName()) {
            'sqlite' => "MAX(0, COALESCE(CAST(json_extract(summary_jsonb, '$.gaps.count') AS INTEGER), 0) - COALESCE(CAST(json_extract(summary_jsonb, '$.gaps.by_reason.meta_fallback') AS INTEGER), 0))",
            'pgsql' => "GREATEST(0, COALESCE((summary_jsonb #>> '{gaps,count}')::int, 0) - COALESCE((summary_jsonb #>> '{gaps,by_reason,meta_fallback}')::int, 0))",
            default => "GREATEST(0, COALESCE(CAST(JSON_EXTRACT(summary_jsonb, '$.gaps.count') AS SIGNED), 0) - COALESCE(CAST(JSON_EXTRACT(summary_jsonb, '$.gaps.by_reason.meta_fallback') AS SIGNED), 0))",
        };
    }

    private static function gapSpec(BaselineSnapshot $snapshot): \App\Support\Badges\BadgeSpec
    {
        return BadgeCatalog::spec(
            BadgeDomain::BaselineSnapshotGapStatus,
            self::hasGaps($snapshot) ? 'gaps_present' : 'clear',
        );
    }

    private static function truthEnvelope(BaselineSnapshot $snapshot, bool $fresh = false): ArtifactTruthEnvelope
    {
        $presenter = app(ArtifactTruthPresenter::class);

        return $fresh
            ? $presenter->forBaselineSnapshotFresh($snapshot)
            : $presenter->forBaselineSnapshot($snapshot);
    }

    private static function truthHeadline(BaselineSnapshot $record): ?string
    {
        return self::truthEnvelope($record)->operatorExplanation?->headline
            ?? self::compressedOutcome($record)->primaryReason;
    }

    private static function compressedOutcome(BaselineSnapshot $snapshot, bool $fresh = false): CompressedGovernanceOutcome
    {
        $presenter = app(ArtifactTruthPresenter::class);

        return $presenter->compressedOutcomeFor($snapshot, SurfaceCompressionContext::baselineSnapshot(), $fresh)
            ?? $presenter->compressedOutcomeFromEnvelope(
                self::truthEnvelope($snapshot, $fresh),
                SurfaceCompressionContext::baselineSnapshot(),
            );
    }

    private static function currentTruthLabel(BaselineSnapshot $snapshot): string
    {
        return match (self::currentTruthState($snapshot)) {
            'current' => 'Current baseline',
            'historical' => 'Historical trace',
            default => 'Not compare input',
        };
    }

    private static function currentTruthDescription(BaselineSnapshot $snapshot): ?string
    {
        return match (self::currentTruthState($snapshot)) {
            'current' => 'Compare resolves to this snapshot as the current baseline truth.',
            'historical' => 'A newer complete snapshot is now the current baseline truth for this profile.',
            default => self::truthEnvelope($snapshot)->primaryExplanation,
        };
    }

    private static function currentTruthColor(BaselineSnapshot $snapshot): string
    {
        return match (self::currentTruthState($snapshot)) {
            'current' => 'success',
            'historical' => 'gray',
            default => 'warning',
        };
    }

    private static function currentTruthIcon(BaselineSnapshot $snapshot): ?string
    {
        return match (self::currentTruthState($snapshot)) {
            'current' => 'heroicon-m-check-badge',
            'historical' => 'heroicon-m-clock',
            default => 'heroicon-m-exclamation-triangle',
        };
    }

    private static function currentTruthState(BaselineSnapshot $snapshot): string
    {
        if (! $snapshot->isConsumable()) {
            return 'unusable';
        }

        return app(BaselineSnapshotTruthResolver::class)->isHistoricallySuperseded($snapshot)
            ? 'historical'
            : 'current';
    }
}
