<?php

namespace App\Filament\Resources\FindingResource\Pages;

use App\Filament\Resources\FindingResource;
use App\Models\Finding;
use App\Models\Tenant;
use App\Models\User;
use Filament\Actions;
use Filament\Forms\Components\TextInput;
use Filament\Notifications\Notification;
use Filament\Resources\Pages\ListRecords;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Gate;

class ListFindings extends ListRecords
{
    protected static string $resource = FindingResource::class;

    protected function getHeaderActions(): array
    {
        return [
            Actions\Action::make('acknowledge_all_matching')
                ->label('Acknowledge all matching')
                ->icon('heroicon-o-check')
                ->color('gray')
                ->requiresConfirmation()
                ->authorize(function (): bool {
                    $tenant = Tenant::current();
                    $user = auth()->user();

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

                    $probe = new Finding(['tenant_id' => $tenant->getKey()]);

                    return $user->can('update', $probe);
                })
                ->visible(fn (): bool => $this->getStatusFilterValue() === Finding::STATUS_NEW)
                ->modalDescription(function (): string {
                    $count = $this->getAllMatchingCount();

                    return "You are about to acknowledge {$count} finding".($count === 1 ? '' : 's').' matching the current filters.';
                })
                ->form(function (): array {
                    $count = $this->getAllMatchingCount();

                    if ($count <= 100) {
                        return [];
                    }

                    return [
                        TextInput::make('confirmation')
                            ->label('Type ACKNOWLEDGE to confirm')
                            ->required()
                            ->in(['ACKNOWLEDGE'])
                            ->validationMessages([
                                'in' => 'Please type ACKNOWLEDGE to confirm.',
                            ]),
                    ];
                })
                ->action(function (array $data): void {
                    $tenant = Tenant::current();
                    $user = auth()->user();

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

                    $query = $this->buildAllMatchingQuery();
                    $count = (clone $query)->count();

                    if ($count === 0) {
                        Notification::make()
                            ->title('No matching findings')
                            ->body('There are no new findings matching the current filters.')
                            ->warning()
                            ->send();

                        return;
                    }

                    $firstRecord = (clone $query)->first();
                    if ($firstRecord instanceof Finding) {
                        Gate::authorize('update', $firstRecord);
                    }

                    $updated = $query->update([
                        'status' => Finding::STATUS_ACKNOWLEDGED,
                        'acknowledged_at' => now(),
                        'acknowledged_by_user_id' => $user->getKey(),
                    ]);

                    $this->deselectAllTableRecords();
                    $this->resetPage();

                    Notification::make()
                        ->title('Bulk acknowledge completed')
                        ->body("Acknowledged {$updated} finding".($updated === 1 ? '' : 's').'.')
                        ->success()
                        ->send();
                }),
        ];
    }

    protected function buildAllMatchingQuery(): Builder
    {
        $tenant = Tenant::current();

        $query = Finding::query();

        if (! $tenant) {
            return $query->whereRaw('1 = 0');
        }

        $query->where('tenant_id', $tenant->getKey());

        $query->where('status', Finding::STATUS_NEW);

        $findingType = $this->getFindingTypeFilterValue();
        if (is_string($findingType) && $findingType !== '') {
            $query->where('finding_type', $findingType);
        }

        $scopeKeyState = $this->getTableFilterState('scope_key') ?? [];
        $scopeKey = Arr::get($scopeKeyState, 'scope_key');
        if (is_string($scopeKey) && $scopeKey !== '') {
            $query->where('scope_key', $scopeKey);
        }

        $runIdsState = $this->getTableFilterState('run_ids') ?? [];
        $baselineRunId = Arr::get($runIdsState, 'baseline_run_id');
        if (is_numeric($baselineRunId)) {
            $query->where('baseline_run_id', (int) $baselineRunId);
        }

        $currentRunId = Arr::get($runIdsState, 'current_run_id');
        if (is_numeric($currentRunId)) {
            $query->where('current_run_id', (int) $currentRunId);
        }

        return $query;
    }

    protected function getAllMatchingCount(): int
    {
        return (int) $this->buildAllMatchingQuery()->count();
    }

    protected function getStatusFilterValue(): string
    {
        $state = $this->getTableFilterState('status') ?? [];
        $value = Arr::get($state, 'value');

        return is_string($value) && $value !== ''
            ? $value
            : Finding::STATUS_NEW;
    }

    protected function getFindingTypeFilterValue(): string
    {
        $state = $this->getTableFilterState('finding_type') ?? [];
        $value = Arr::get($state, 'value');

        return is_string($value) && $value !== ''
            ? $value
            : Finding::FINDING_TYPE_DRIFT;
    }
}
