<?php

namespace App\Filament\Resources;

use App\Filament\Resources\ReviewPackResource\Pages;
use App\Models\ReviewPack;
use App\Models\Tenant;
use App\Models\User;
use App\Services\ReviewPackService;
use App\Support\Auth\Capabilities;
use App\Support\Badges\BadgeDomain;
use App\Support\Badges\BadgeRenderer;
use App\Support\OpsUx\OperationUxPresenter;
use App\Support\Rbac\UiEnforcement;
use App\Support\ReviewPackStatus;
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 BackedEnum;
use Filament\Actions;
use Filament\Facades\Filament;
use Filament\Forms\Components\Toggle;
use Filament\Infolists\Components\TextEntry;
use Filament\Notifications\Notification;
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 Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Number;
use UnitEnum;

class ReviewPackResource extends Resource
{
    protected static ?string $model = ReviewPack::class;

    protected static ?string $tenantOwnershipRelationshipName = 'tenant';

    protected static bool $isGloballySearchable = false;

    protected static string|BackedEnum|null $navigationIcon = 'heroicon-o-document-arrow-down';

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

    protected static ?string $navigationLabel = 'Review Packs';

    protected static ?int $navigationSort = 50;

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

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

        if (! $user->canAccessTenant($tenant)) {
            return false;
        }

        return $user->can(Capabilities::REVIEW_PACK_VIEW, $tenant);
    }

    public static function canView(Model $record): bool
    {
        $tenant = Tenant::current();
        $user = auth()->user();

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

        if (! $user->canAccessTenant($tenant)) {
            return false;
        }

        if (! $user->can(Capabilities::REVIEW_PACK_VIEW, $tenant)) {
            return false;
        }

        if ($record instanceof ReviewPack) {
            return (int) $record->tenant_id === (int) $tenant->getKey();
        }

        return true;
    }

    public static function actionSurfaceDeclaration(): ActionSurfaceDeclaration
    {
        return ActionSurfaceDeclaration::forResource(ActionSurfaceProfile::CrudListAndView)
            ->satisfy(ActionSurfaceSlot::ListHeader, 'Generate Pack action available in list header.')
            ->satisfy(ActionSurfaceSlot::InspectAffordance, ActionSurfaceInspectAffordance::ViewAction->value)
            ->satisfy(ActionSurfaceSlot::ListEmptyState, 'Empty state includes Generate CTA.')
            ->exempt(ActionSurfaceSlot::ListRowMoreMenu, 'Only two primary row actions (Download, Expire); no secondary menu needed.')
            ->exempt(ActionSurfaceSlot::ListBulkMoreGroup, 'No bulk operations are supported for review packs.')
            ->satisfy(ActionSurfaceSlot::DetailHeader, 'Download and Regenerate actions in ViewReviewPack header.');
    }

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

    public static function infolist(Schema $schema): Schema
    {
        return $schema
            ->schema([
                Section::make('Status')
                    ->schema([
                        TextEntry::make('status')
                            ->badge()
                            ->formatStateUsing(BadgeRenderer::label(BadgeDomain::ReviewPackStatus))
                            ->color(BadgeRenderer::color(BadgeDomain::ReviewPackStatus))
                            ->icon(BadgeRenderer::icon(BadgeDomain::ReviewPackStatus))
                            ->iconColor(BadgeRenderer::iconColor(BadgeDomain::ReviewPackStatus)),
                        TextEntry::make('tenant.name')->label('Tenant'),
                        TextEntry::make('generated_at')->dateTime()->placeholder('—'),
                        TextEntry::make('expires_at')->dateTime()->placeholder('—'),
                        TextEntry::make('file_size')
                            ->label('File size')
                            ->formatStateUsing(fn ($state): string => $state ? Number::fileSize((int) $state) : '—'),
                        TextEntry::make('sha256')->label('SHA-256')->copyable()->placeholder('—'),
                    ])
                    ->columns(2)
                    ->columnSpanFull(),

                Section::make('Summary')
                    ->schema([
                        TextEntry::make('summary.finding_count')->label('Findings')->placeholder('—'),
                        TextEntry::make('summary.report_count')->label('Reports')->placeholder('—'),
                        TextEntry::make('summary.operation_count')->label('Operations')->placeholder('—'),
                        TextEntry::make('summary.data_freshness.permission_posture')
                            ->label('Permission posture freshness')
                            ->placeholder('—'),
                        TextEntry::make('summary.data_freshness.entra_admin_roles')
                            ->label('Entra admin roles freshness')
                            ->placeholder('—'),
                        TextEntry::make('summary.data_freshness.findings')
                            ->label('Findings freshness')
                            ->placeholder('—'),
                        TextEntry::make('summary.data_freshness.hardening')
                            ->label('Hardening freshness')
                            ->placeholder('—'),
                    ])
                    ->columns(2)
                    ->columnSpanFull(),

                Section::make('Options')
                    ->schema([
                        TextEntry::make('options.include_pii')
                            ->label('Include PII')
                            ->formatStateUsing(fn ($state): string => $state ? 'Yes' : 'No'),
                        TextEntry::make('options.include_operations')
                            ->label('Include operations')
                            ->formatStateUsing(fn ($state): string => $state ? 'Yes' : 'No'),
                    ])
                    ->columns(2)
                    ->columnSpanFull(),

                Section::make('Metadata')
                    ->schema([
                        TextEntry::make('initiator.name')->label('Initiated by')->placeholder('—'),
                        TextEntry::make('operationRun.id')
                            ->label('Operation run')
                            ->url(fn (ReviewPack $record): ?string => $record->operation_run_id
                                ? route('admin.operations.view', ['run' => (int) $record->operation_run_id])
                                : null)
                            ->openUrlInNewTab()
                            ->placeholder('—'),
                        TextEntry::make('fingerprint')->label('Fingerprint')->copyable()->placeholder('—'),
                        TextEntry::make('previous_fingerprint')->label('Previous fingerprint')->copyable()->placeholder('—'),
                        TextEntry::make('created_at')->label('Created')->dateTime(),
                    ])
                    ->columns(2)
                    ->columnSpanFull(),
            ]);
    }

    public static function table(Table $table): Table
    {
        return $table
            ->defaultSort('created_at', 'desc')
            ->paginated(\App\Support\Filament\TablePaginationProfiles::resource())
            ->recordUrl(fn (ReviewPack $record): string => static::getUrl('view', ['record' => $record]))
            ->columns([
                Tables\Columns\TextColumn::make('status')
                    ->badge()
                    ->formatStateUsing(BadgeRenderer::label(BadgeDomain::ReviewPackStatus))
                    ->color(BadgeRenderer::color(BadgeDomain::ReviewPackStatus))
                    ->icon(BadgeRenderer::icon(BadgeDomain::ReviewPackStatus))
                    ->iconColor(BadgeRenderer::iconColor(BadgeDomain::ReviewPackStatus))
                    ->sortable(),
                Tables\Columns\TextColumn::make('tenant.name')
                    ->label('Tenant')
                    ->searchable(),
                Tables\Columns\TextColumn::make('generated_at')
                    ->dateTime()
                    ->sortable()
                    ->placeholder('—'),
                Tables\Columns\TextColumn::make('expires_at')
                    ->dateTime()
                    ->sortable()
                    ->placeholder('—'),
                Tables\Columns\TextColumn::make('file_size')
                    ->label('Size')
                    ->formatStateUsing(fn ($state): string => $state ? Number::fileSize((int) $state) : '—')
                    ->sortable(),
                Tables\Columns\TextColumn::make('created_at')
                    ->label('Created')
                    ->since()
                    ->toggleable(isToggledHiddenByDefault: true),
            ])
            ->filters([
                Tables\Filters\SelectFilter::make('status')
                    ->options(collect(ReviewPackStatus::cases())
                        ->mapWithKeys(fn (ReviewPackStatus $s): array => [$s->value => ucfirst($s->value)])
                        ->all()),
            ])
            ->actions([
                Actions\Action::make('download')
                    ->label('Download')
                    ->icon('heroicon-o-arrow-down-tray')
                    ->color('success')
                    ->visible(fn (ReviewPack $record): bool => $record->status === ReviewPackStatus::Ready->value)
                    ->url(function (ReviewPack $record): string {
                        return app(ReviewPackService::class)->generateDownloadUrl($record);
                    })
                    ->openUrlInNewTab(),
                UiEnforcement::forAction(
                    Actions\Action::make('expire')
                        ->label('Expire')
                        ->icon('heroicon-o-clock')
                        ->color('danger')
                        ->visible(fn (ReviewPack $record): bool => $record->status === ReviewPackStatus::Ready->value)
                        ->requiresConfirmation()
                        ->modalDescription('This will mark the pack as expired and delete the file. This cannot be undone.')
                        ->action(function (ReviewPack $record): void {
                            if ($record->file_path && $record->file_disk) {
                                \Illuminate\Support\Facades\Storage::disk($record->file_disk)->delete($record->file_path);
                            }

                            $record->update(['status' => ReviewPackStatus::Expired->value]);

                            Notification::make()
                                ->success()
                                ->title('Review pack expired')
                                ->send();
                        })
                )
                    ->preserveVisibility()
                    ->requireCapability(Capabilities::REVIEW_PACK_MANAGE)
                    ->apply(),
            ])
            ->emptyStateHeading('No review packs yet')
            ->emptyStateDescription('Generate a review pack to export tenant data for external review.')
            ->emptyStateIcon('heroicon-o-document-arrow-down')
            ->emptyStateActions([
                UiEnforcement::forAction(
                    Actions\Action::make('generate_first')
                        ->label('Generate first pack')
                        ->icon('heroicon-o-plus')
                        ->action(function (array $data): void {
                            static::executeGeneration($data);
                        })
                        ->form([
                            Section::make('Pack options')
                                ->schema([
                                    Toggle::make('include_pii')
                                        ->label('Include PII')
                                        ->helperText('Include personally identifiable information in the export.')
                                        ->default(config('tenantpilot.review_pack.include_pii_default', true)),
                                    Toggle::make('include_operations')
                                        ->label('Include operations')
                                        ->helperText('Include recent operation history in the export.')
                                        ->default(config('tenantpilot.review_pack.include_operations_default', true)),
                                ]),
                        ])
                )
                    ->requireCapability(Capabilities::REVIEW_PACK_MANAGE)
                    ->apply(),
            ]);
    }

    public static function getEloquentQuery(): Builder
    {
        $tenant = Filament::getTenant();

        if (! $tenant instanceof Tenant) {
            return parent::getEloquentQuery()->whereRaw('1 = 0');
        }

        return parent::getEloquentQuery()->where('tenant_id', (int) $tenant->getKey());
    }

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

    /**
     * @param  array<string, mixed>  $data
     */
    public static function executeGeneration(array $data): void
    {
        $tenant = Filament::getTenant();
        $user = auth()->user();

        if (! $tenant instanceof Tenant || ! $user instanceof User) {
            Notification::make()->danger()->title('Unable to generate pack — missing context.')->send();

            return;
        }

        $service = app(ReviewPackService::class);

        if ($service->checkActiveRun($tenant)) {
            Notification::make()->warning()->title('A review pack is already being generated.')->send();

            return;
        }

        $options = [
            'include_pii' => (bool) ($data['include_pii'] ?? true),
            'include_operations' => (bool) ($data['include_operations'] ?? true),
        ];

        $reviewPack = $service->generate($tenant, $user, $options);

        if (! $reviewPack->wasRecentlyCreated) {
            Notification::make()
                ->success()
                ->title('Review pack already available')
                ->body('A matching review pack is already ready. No new run was started.')
                ->actions([
                    Actions\Action::make('view_pack')
                        ->label('View pack')
                        ->url(static::getUrl('view', ['record' => $reviewPack], tenant: $tenant)),
                ])
                ->send();

            return;
        }

        OperationUxPresenter::queuedToast('tenant.review_pack.generate')->send();
    }
}
