<?php

declare(strict_types=1);

namespace App\Filament\Widgets\Dashboard;

use App\Filament\Resources\FindingResource;
use App\Models\FindingException;
use App\Models\ManagedEnvironment;
use App\Models\OperationRun;
use App\Models\User;
use App\Support\Auth\Capabilities;
use App\Support\Baselines\BaselineCompareSummaryAssessment;
use App\Support\Baselines\TenantGovernanceAggregate;
use App\Support\Baselines\TenantGovernanceAggregateResolver;
use App\Support\ManagedEnvironmentLinks;
use App\Support\OperationRunLinks;
use App\Support\Rbac\UiTooltips;
use Filament\Facades\Filament;
use Filament\Widgets\Widget;

class BaselineCompareNow extends Widget
{
    protected string $view = 'filament.widgets.dashboard.baseline-compare-now';

    /**
     * @return array<string, mixed>
     */
    protected function getViewData(): array
    {
        $tenant = Filament::getTenant();

        $empty = [
            'hasAssignment' => false,
            'profileName' => null,
            'lastComparedAt' => null,
            'landingUrl' => null,
            'runUrl' => null,
            'findingsUrl' => null,
            'nextActionLabel' => null,
            'nextActionUrl' => null,
            'nextActionHelperText' => null,
            'summaryAssessment' => null,
        ];

        if (! $tenant instanceof ManagedEnvironment) {
            return $empty;
        }

        $aggregate = $this->governanceAggregate($tenant);

        if ($aggregate->compareState === 'no_assignment') {
            return $empty;
        }

        $tenantLandingUrl = ManagedEnvironmentLinks::baselineCompareUrl($tenant);
        $operationsFollowUpCount = (int) OperationRun::query()
            ->where('managed_environment_id', (int) $tenant->getKey())
            ->dashboardNeedsFollowUp()
            ->count();
        $summaryAssessment = $this->dashboardSummaryAssessment($aggregate, $operationsFollowUpCount);
        $runUrl = $this->runUrl($tenant, $aggregate);
        $findingsUrl = $this->findingsUrl($tenant, $aggregate);
        $nextActionTarget = (string) ($summaryAssessment['dashboardNextActionTarget'] ?? (($summaryAssessment['nextAction']['target'] ?? 'none') ?: 'none'));
        $nextActionLabel = (string) ($summaryAssessment['nextAction']['label'] ?? '');
        $nextActionUrl = match ($nextActionTarget) {
            'run' => $runUrl,
            'findings' => $findingsUrl,
            'landing' => $tenantLandingUrl,
            'operations' => OperationRunLinks::index($tenant, activeTab: 'blocked'),
            default => null,
        };
        $nextActionHelperText = in_array($nextActionTarget, ['run', 'findings'], true) && $nextActionUrl === null
            ? UiTooltips::INSUFFICIENT_PERMISSION
            : null;

        return [
            'hasAssignment' => true,
            'profileName' => $aggregate->profileName,
            'lastComparedAt' => $aggregate->lastComparedLabel,
            'landingUrl' => $tenantLandingUrl,
            'runUrl' => $runUrl,
            'findingsUrl' => $findingsUrl,
            'nextActionLabel' => $nextActionLabel !== '' ? $nextActionLabel : null,
            'nextActionUrl' => $nextActionUrl,
            'nextActionHelperText' => $nextActionHelperText,
            'summaryAssessment' => $summaryAssessment,
        ];
    }

    /**
     * @return array<string, mixed>
     */
    private function dashboardSummaryAssessment(TenantGovernanceAggregate $aggregate, int $operationsFollowUpCount): array
    {
        $summaryAssessment = $aggregate->summaryAssessment->toArray();

        if (($summaryAssessment['stateFamily'] ?? null) !== BaselineCompareSummaryAssessment::STATE_POSITIVE) {
            return $summaryAssessment;
        }

        if ($aggregate->highSeverityActiveFindingsCount > 0) {
            $count = $aggregate->highSeverityActiveFindingsCount;

            return array_merge($summaryAssessment, [
                'stateFamily' => BaselineCompareSummaryAssessment::STATE_ACTION_REQUIRED,
                'tone' => 'danger',
                'headline' => sprintf('%d high-severity active finding%s need review.', $count, $count === 1 ? '' : 's'),
                'supportingMessage' => 'The latest compare may be healthy, but the tenant still has active high-severity findings.',
                'highSeverityCount' => $count,
                'nextAction' => [
                    'label' => 'Open findings',
                    'target' => BaselineCompareSummaryAssessment::NEXT_TARGET_FINDINGS,
                ],
                'dashboardNextActionTarget' => 'findings',
            ]);
        }

        if ($operationsFollowUpCount > 0) {
            return array_merge($summaryAssessment, [
                'stateFamily' => BaselineCompareSummaryAssessment::STATE_ACTION_REQUIRED,
                'tone' => 'danger',
                'headline' => sprintf('%d operation%s need follow-up.', $operationsFollowUpCount, $operationsFollowUpCount === 1 ? '' : 's'),
                'supportingMessage' => 'Failed, warning, or stalled runs still need review before this tenant reads as fully calm.',
                'nextAction' => [
                    'label' => 'Open operations',
                    'target' => BaselineCompareSummaryAssessment::NEXT_TARGET_NONE,
                ],
                'dashboardNextActionTarget' => 'operations',
            ]);
        }

        return $summaryAssessment;
    }

    private function runUrl(ManagedEnvironment $tenant, TenantGovernanceAggregate $aggregate): ?string
    {
        $runId = $aggregate->stats->operationRunId;

        if (! is_int($runId)) {
            return null;
        }

        $run = OperationRun::query()->find($runId);

        if (! $run instanceof OperationRun || ! $this->canOpenRun($run)) {
            return null;
        }

        return OperationRunLinks::view($run, $tenant);
    }

    private function findingsUrl(ManagedEnvironment $tenant, TenantGovernanceAggregate $aggregate): ?string
    {
        if (! $this->canOpenFindings($tenant)) {
            return null;
        }

        $parameters = match (true) {
            $aggregate->lapsedGovernanceCount > 0 => [
                'tab' => 'risk_accepted',
                'governance_validity' => FindingException::VALIDITY_MISSING_SUPPORT,
            ],
            $aggregate->overdueOpenFindingsCount > 0 => [
                'tab' => 'overdue',
            ],
            $aggregate->expiringGovernanceCount > 0 => [
                'tab' => 'risk_accepted',
                'governance_validity' => FindingException::VALIDITY_EXPIRING,
            ],
            $aggregate->highSeverityActiveFindingsCount > 0 => [
                'tab' => 'needs_action',
                'high_severity' => 1,
            ],
            $aggregate->visibleDriftFindingsCount > 0 => [
                'tab' => 'needs_action',
                'finding_type' => 'drift',
            ],
            default => [],
        };

        return FindingResource::getUrl('index', $parameters, tenant: $tenant);
    }

    private function canOpenFindings(ManagedEnvironment $tenant): bool
    {
        $user = auth()->user();

        return $user instanceof User
            && $user->canAccessTenant($tenant)
            && $user->can(Capabilities::TENANT_FINDINGS_VIEW, $tenant);
    }

    private function canOpenRun(OperationRun $run): bool
    {
        $user = auth()->user();

        return $user instanceof User && $user->can('view', $run);
    }

    private function governanceAggregate(ManagedEnvironment $tenant): TenantGovernanceAggregate
    {
        /** @var TenantGovernanceAggregateResolver $resolver */
        $resolver = app(TenantGovernanceAggregateResolver::class);

        /** @var TenantGovernanceAggregate $aggregate */
        $aggregate = $resolver->forTenant($tenant);

        return $aggregate;
    }
}
