<?php

declare(strict_types=1);

namespace App\Support\EnvironmentDashboard;

use App\Filament\Pages\Reviews\CustomerReviewWorkspace;
use App\Filament\Resources\BackupScheduleResource;
use App\Filament\Resources\BackupSetResource;
use App\Filament\Resources\EnvironmentReviewResource;
use App\Filament\Resources\EvidenceSnapshotResource;
use App\Filament\Resources\FindingExceptionResource;
use App\Filament\Resources\FindingResource;
use App\Filament\Resources\ReviewPackResource;
use App\Models\EnvironmentReview;
use App\Models\EvidenceSnapshot;
use App\Models\Finding;
use App\Models\FindingException;
use App\Models\ManagedEnvironment;
use App\Models\OperationRun;
use App\Models\ProviderConnection;
use App\Models\ReviewPack;
use App\Models\User;
use App\Services\Intune\ManagedEnvironmentRequiredPermissionsViewModelBuilder;
use App\Support\Auth\Capabilities;
use App\Support\BackupHealth\BackupHealthActionTarget;
use App\Support\BackupHealth\TenantBackupHealthAssessment;
use App\Support\BackupHealth\TenantBackupHealthResolver;
use App\Support\Badges\BadgeDomain;
use App\Support\Badges\BadgeRenderer;
use App\Support\Baselines\TenantGovernanceAggregate;
use App\Support\Baselines\TenantGovernanceAggregateResolver;
use App\Support\Links\RequiredPermissionsLinks;
use App\Support\ManagedEnvironmentLinks;
use App\Support\OperationCatalog;
use App\Support\OperationRunLinks;
use App\Support\OperationRunOutcome;
use App\Support\OpsUx\ActiveRuns;
use App\Support\OpsUx\OperationUxPresenter;
use App\Support\RestoreSafety\RestoreSafetyResolver;
use App\Support\Tenants\TenantRecoveryTriagePresentation;
use App\Support\Verification\VerificationReportOverall;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Carbon;
use Illuminate\Support\Collection;
use Illuminate\Support\Str;

final class EnvironmentDashboardSummaryBuilder
{
    public function __construct(
        private readonly TenantGovernanceAggregateResolver $tenantGovernanceAggregateResolver,
        private readonly TenantBackupHealthResolver $tenantBackupHealthResolver,
        private readonly RestoreSafetyResolver $restoreSafetyResolver,
        private readonly ManagedEnvironmentRequiredPermissionsViewModelBuilder $tenantRequiredPermissionsViewModelBuilder,
    ) {}

    public function build(ManagedEnvironment $tenant, ?User $user = null): EnvironmentDashboardSummary
    {
        $tenant->loadMissing('workspace', 'providerConnections');

        $user = $user ?? auth()->user();
        $request = app()->bound('request') ? request() : null;
        $cacheKey = sprintf(
            'tenant_dashboard.summary.%d.%s',
            (int) $tenant->getKey(),
            $user instanceof User ? (string) $user->getKey() : 'guest',
        );

        if ($request?->attributes->has($cacheKey)) {
            $cached = $request->attributes->get($cacheKey);

            if ($cached instanceof EnvironmentDashboardSummary) {
                return $cached;
            }
        }

        $primaryProviderConnection = $this->primaryProviderConnection($tenant);

        $aggregate = $this->tenantGovernanceAggregateResolver->forTenant($tenant);
        $backupHealth = $this->tenantBackupHealthResolver->assess($tenant);
        $recoveryEvidence = $this->restoreSafetyResolver->dashboardRecoveryEvidence($tenant);
        $requiredPermissions = $this->tenantRequiredPermissionsViewModelBuilder->build($tenant, [
            'status' => 'missing',
        ]);

        $latestReview = $this->latestEnvironmentReview($tenant);
        $latestReviewPack = $this->latestReviewPack($tenant);
        $latestEvidenceSnapshot = $this->latestEvidenceSnapshot($tenant);
        $exceptionStats = $this->exceptionStats($tenant);
        $recentOperations = $this->recentOperations($tenant);

        $recommendedActions = $this->recommendedActions(
            tenant: $tenant,
            user: $user,
            aggregate: $aggregate,
            backupHealth: $backupHealth,
            recoveryEvidence: $recoveryEvidence,
            requiredPermissions: $requiredPermissions,
            latestReview: $latestReview,
            latestReviewPack: $latestReviewPack,
            exceptionStats: $exceptionStats,
        );

        $summary = new EnvironmentDashboardSummary(
            context: [
                'workspace' => (string) ($tenant->workspace?->name ?? $this->overviewText('context_workspace')),
                'tenant' => (string) $tenant->name,
                'provider' => $this->providerChipLabel($primaryProviderConnection),
                'providerKey' => $this->providerChipKey($primaryProviderConnection),
                'latestActivity' => $this->latestActivityLabel(
                    primaryProviderConnection: $primaryProviderConnection,
                    latestReview: $latestReview,
                    latestReviewPack: $latestReviewPack,
                    latestEvidenceSnapshot: $latestEvidenceSnapshot,
                    recentOperations: $recentOperations,
                ),
            ],
            posture: $this->posture(
                aggregate: $aggregate,
                backupHealth: $backupHealth,
                recoveryEvidence: $recoveryEvidence,
                requiredPermissions: $requiredPermissions,
                recommendedActions: $recommendedActions,
            ),
            kpis: $this->kpis($tenant, $user, $aggregate, $requiredPermissions),
            recommendedActions: $recommendedActions,
            governanceStatus: $this->governanceStatus(
                tenant: $tenant,
                user: $user,
                aggregate: $aggregate,
                backupHealth: $backupHealth,
                requiredPermissions: $requiredPermissions,
                latestReview: $latestReview,
                latestEvidenceSnapshot: $latestEvidenceSnapshot,
            ),
            readinessCards: $this->readinessCards(
                tenant: $tenant,
                user: $user,
                primaryProviderConnection: $primaryProviderConnection,
                requiredPermissions: $requiredPermissions,
                latestReview: $latestReview,
                latestReviewPack: $latestReviewPack,
                latestEvidenceSnapshot: $latestEvidenceSnapshot,
                exceptionStats: $exceptionStats,
            ),
            activeOperationSummary: $this->activeOperationSummary($tenant, $user),
            recentOperations: $this->recentOperationCards($tenant, $recentOperations),
            pollingInterval: ActiveRuns::pollingIntervalForTenant($tenant),
        );

        $request?->attributes->set($cacheKey, $summary);

        return $summary;
    }

    private function primaryProviderConnection(ManagedEnvironment $tenant): ?ProviderConnection
    {
        $connections = $tenant->providerConnections;

        return $connections->first(static fn (ProviderConnection $connection): bool => $connection->is_enabled && $connection->is_default)
            ?? $connections->first(static fn (ProviderConnection $connection): bool => $connection->is_enabled)
            ?? $connections->first();
    }

    private function providerChipLabel(?ProviderConnection $connection): ?string
    {
        if (! $connection instanceof ProviderConnection || blank($connection->provider)) {
            return null;
        }

        return Str::headline((string) $connection->provider);
    }

    private function providerChipKey(?ProviderConnection $connection): ?string
    {
        if (! $connection instanceof ProviderConnection || blank($connection->provider)) {
            return null;
        }

        return Str::lower((string) $connection->provider);
    }

    /**
     * @param  list<OperationRun>  $recentOperations
     */
    private function latestActivityLabel(
        ?ProviderConnection $primaryProviderConnection,
        ?EnvironmentReview $latestReview,
        ?ReviewPack $latestReviewPack,
        ?EvidenceSnapshot $latestEvidenceSnapshot,
        array $recentOperations,
    ): ?string {
        $timestamp = $this->latestActivityTimestamp(
            primaryProviderConnection: $primaryProviderConnection,
            latestReview: $latestReview,
            latestReviewPack: $latestReviewPack,
            latestEvidenceSnapshot: $latestEvidenceSnapshot,
            recentOperations: $recentOperations,
        );

        return $timestamp?->diffForHumans();
    }

    /**
     * @param  list<OperationRun>  $recentOperations
     */
    private function latestActivityTimestamp(
        ?ProviderConnection $primaryProviderConnection,
        ?EnvironmentReview $latestReview,
        ?ReviewPack $latestReviewPack,
        ?EvidenceSnapshot $latestEvidenceSnapshot,
        array $recentOperations,
    ): ?Carbon {
        $candidates = [];

        foreach ($recentOperations as $operation) {
            $timestamp = $operation->completed_at ?? $operation->created_at;

            if ($timestamp instanceof Carbon) {
                $candidates[] = $timestamp;
            }
        }

        foreach ([
            $primaryProviderConnection?->last_health_check_at,
            $primaryProviderConnection?->consent_last_checked_at,
            $latestReview?->published_at ?? $latestReview?->generated_at,
            $latestReviewPack?->generated_at,
            $latestEvidenceSnapshot?->generated_at,
        ] as $timestamp) {
            if ($timestamp instanceof Carbon) {
                $candidates[] = $timestamp;
            }
        }

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

        usort($candidates, static fn (Carbon $left, Carbon $right): int => $right->getTimestamp() <=> $left->getTimestamp());

        return $candidates[0];
    }

    private function latestEnvironmentReview(ManagedEnvironment $tenant): ?EnvironmentReview
    {
        return EnvironmentReview::query()
            ->with(['tenant', 'evidenceSnapshot', 'currentExportReviewPack'])
            ->where('managed_environment_id', (int) $tenant->getKey())
            ->latest('generated_at')
            ->latest('id')
            ->first();
    }

    private function latestReviewPack(ManagedEnvironment $tenant): ?ReviewPack
    {
        return ReviewPack::query()
            ->with(['tenant', 'environmentReview'])
            ->where('managed_environment_id', (int) $tenant->getKey())
            ->latest('generated_at')
            ->latest('id')
            ->first();
    }

    private function latestEvidenceSnapshot(ManagedEnvironment $tenant): ?EvidenceSnapshot
    {
        return EvidenceSnapshot::query()
            ->where('managed_environment_id', (int) $tenant->getKey())
            ->latest('generated_at')
            ->latest('id')
            ->first();
    }

    /**
     * @return array{active:int,expiring:int,expired:int,pending:int,total:int}
     */
    private function exceptionStats(ManagedEnvironment $tenant): array
    {
        $counts = FindingException::query()
            ->where('managed_environment_id', (int) $tenant->getKey())
            ->where('workspace_id', (int) $tenant->workspace_id)
            ->selectRaw('count(*) as total')
            ->selectRaw("count(*) filter (where status = 'active') as active")
            ->selectRaw("count(*) filter (where status = 'expiring') as expiring")
            ->selectRaw("count(*) filter (where status = 'expired') as expired")
            ->selectRaw("count(*) filter (where status = 'pending') as pending")
            ->first();

        return [
            'active' => (int) ($counts?->active ?? 0),
            'expiring' => (int) ($counts?->expiring ?? 0),
            'expired' => (int) ($counts?->expired ?? 0),
            'pending' => (int) ($counts?->pending ?? 0),
            'total' => (int) ($counts?->total ?? 0),
        ];
    }

    /**
     * @return list<OperationRun>
     */
    private function recentOperations(ManagedEnvironment $tenant): array
    {
        return OperationRun::query()
            ->where('managed_environment_id', (int) $tenant->getKey())
            ->latest('created_at')
            ->latest('id')
            ->limit(4)
            ->get()
            ->all();
    }

    /**
     * @param  array<string, mixed>  $requiredPermissions
     * @param  list<array<string, mixed>>  $recommendedActions
     * @return array{status:string,tone:string,headline:string,summary:string}
     */
    private function posture(
        TenantGovernanceAggregate $aggregate,
        TenantBackupHealthAssessment $backupHealth,
        array $recoveryEvidence,
        array $requiredPermissions,
        array $recommendedActions,
    ): array {
        $counts = is_array($requiredPermissions['overview']['counts'] ?? null)
            ? $requiredPermissions['overview']['counts']
            : [];
        $missingApplicationPermissions = (int) ($counts['missing_application'] ?? 0);

        if ($missingApplicationPermissions > 0) {
            return [
                'status' => $this->overviewText('status_blocked'),
                'tone' => 'danger',
                'headline' => $this->overviewText('posture_blocked_headline'),
                'summary' => $this->overviewText('posture_blocked_summary'),
            ];
        }

        if ($recommendedActions !== [] || $aggregate->stateFamily !== 'positive' || $backupHealth->posture !== TenantBackupHealthAssessment::POSTURE_HEALTHY || TenantRecoveryTriagePresentation::recoveryEvidenceState($recoveryEvidence) !== TenantRecoveryTriagePresentation::RECOVERY_EVIDENCE_NO_RECENT_ISSUES_VISIBLE) {
            $topAction = $recommendedActions[0] ?? null;

            return [
                'status' => $this->overviewText('status_action_needed'),
                'tone' => (string) ($topAction['tone'] ?? 'warning'),
                'headline' => is_string($topAction['reason'] ?? null)
                    ? (string) $topAction['reason']
                    : $aggregate->headline,
                'summary' => is_string($topAction['impact'] ?? null)
                    ? (string) $topAction['impact']
                    : ($aggregate->supportingMessage ?? $this->overviewText('posture_action_needed_fallback_summary')),
            ];
        }

        return [
            'status' => $this->overviewText('status_calm'),
            'tone' => 'success',
            'headline' => $this->overviewText('posture_calm_headline'),
            'summary' => $this->overviewText('posture_calm_summary'),
        ];
    }

    /**
     * @param  array<string, mixed>  $requiredPermissions
     * @return list<array<string, mixed>>
     */
    private function kpis(ManagedEnvironment $tenant, ?User $user, TenantGovernanceAggregate $aggregate, array $requiredPermissions): array
    {
        $counts = is_array($requiredPermissions['overview']['counts'] ?? null)
            ? $requiredPermissions['overview']['counts']
            : [];
        $missingApplicationPermissions = (int) ($counts['missing_application'] ?? 0);
        $missingDelegatedPermissions = (int) ($counts['missing_delegated'] ?? 0);
        $highSeverityChart = $this->highSeverityFindingsChart($tenant);
        $operationsFollowUpChart = $this->operationsFollowUpChart($tenant);

        $operationsNeedingFollowUp = (int) $this->operationsRequiringAttentionQuery($tenant)->count();

        return [
            $this->metricCard(
                key: 'high_severity_findings',
                label: $this->overviewText('kpi_high_severity_label'),
                value: $aggregate->highSeverityActiveFindingsCount,
                description: $this->highSeverityKpiDescription($aggregate->highSeverityActiveFindingsCount, $highSeverityChart),
                tone: $aggregate->highSeverityActiveFindingsCount > 0 ? 'danger' : 'gray',
                icon: $this->trendDirectionIcon($aggregate->highSeverityActiveFindingsCount > 0),
                chart: $highSeverityChart,
                action: $this->tenantFindingsAction($tenant, $user, $this->overviewText('action_review_findings'), [
                    'tab' => 'needs_action',
                    'high_severity' => 1,
                ]),
            ),
            $this->metricCard(
                key: 'overdue_findings',
                label: $this->overviewText('kpi_overdue_label'),
                value: $aggregate->overdueOpenFindingsCount,
                description: $this->overdueKpiDescription($aggregate->overdueOpenFindingsCount),
                tone: $aggregate->overdueOpenFindingsCount > 0 ? 'warning' : 'gray',
                icon: $this->trendDirectionIcon($aggregate->overdueOpenFindingsCount > 0),
                action: $this->tenantFindingsAction($tenant, $user, $this->overviewText('action_open_overdue_findings'), [
                    'tab' => 'overdue',
                ]),
            ),
            $this->metricCard(
                key: 'missing_permissions',
                label: $this->overviewText('kpi_missing_permissions_label'),
                value: $missingApplicationPermissions + $missingDelegatedPermissions,
                description: $this->missingPermissionsKpiDescription($missingApplicationPermissions, $missingDelegatedPermissions),
                tone: $missingApplicationPermissions > 0
                    ? 'danger'
                    : ($missingDelegatedPermissions > 0 ? 'warning' : 'gray'),
                icon: $this->trendDirectionIcon(($missingApplicationPermissions + $missingDelegatedPermissions) > 0),
                action: $this->requiredPermissionsAction($tenant, $user, $this->overviewText('action_open_required_permissions')),
            ),
            $this->metricCard(
                key: 'active_operations',
                label: $this->overviewText('kpi_active_operations_label'),
                value: $operationsNeedingFollowUp,
                description: $this->activeOperationsKpiDescription($operationsNeedingFollowUp, $operationsFollowUpChart),
                tone: $operationsNeedingFollowUp > 0 ? 'warning' : 'gray',
                icon: $this->trendDirectionIcon($operationsNeedingFollowUp > 0),
                chart: $operationsFollowUpChart,
                action: $this->operationsAction(
                    tenant: $tenant,
                    user: $user,
                    label: $this->overviewText('action_open_operations_hub'),
                    activeTab: $operationsNeedingFollowUp > 0 ? OperationRun::PROBLEM_CLASS_TERMINAL_FOLLOW_UP : 'active',
                    problemClass: $operationsNeedingFollowUp > 0 ? OperationRun::PROBLEM_CLASS_TERMINAL_FOLLOW_UP : null,
                ),
            ),
        ];
    }

    /**
     * @param  list<int>|null  $chart
     */
    private function highSeverityKpiDescription(int $count, ?array $chart): string
    {
        if ($count <= 0) {
            return $this->overviewText('kpi_high_severity_tendency_none');
        }

        $windowCount = $chart === null ? 0 : array_sum($chart);

        if ($windowCount > 0) {
            return $this->overviewText('kpi_high_severity_tendency_window', [
                'count' => $count,
                'window' => $windowCount,
            ]);
        }

        return $this->overviewText('kpi_high_severity_tendency', ['count' => $count]);
    }

    private function overdueKpiDescription(int $count): string
    {
        if ($count <= 0) {
            return $this->overviewText('kpi_overdue_tendency_none');
        }

        return $this->overviewText('kpi_overdue_tendency', ['count' => $count]);
    }

    private function missingPermissionsKpiDescription(int $missingApplicationPermissions, int $missingDelegatedPermissions): string
    {
        $totalMissingPermissions = $missingApplicationPermissions + $missingDelegatedPermissions;

        if ($totalMissingPermissions <= 0) {
            return $this->overviewText('kpi_missing_permissions_tendency_none');
        }

        if ($missingApplicationPermissions > 0 && $missingDelegatedPermissions > 0) {
            return $this->overviewText('kpi_missing_permissions_tendency_split', [
                'app' => $missingApplicationPermissions,
                'delegated' => $missingDelegatedPermissions,
            ]);
        }

        if ($missingApplicationPermissions > 0) {
            return $this->overviewText('kpi_missing_permissions_tendency_app_only', [
                'count' => $missingApplicationPermissions,
            ]);
        }

        return $this->overviewText('kpi_missing_permissions_tendency_delegated_only', [
            'count' => $missingDelegatedPermissions,
        ]);
    }

    /**
     * @param  list<int>|null  $chart
     */
    private function activeOperationsKpiDescription(int $count, ?array $chart): string
    {
        if ($count <= 0) {
            return $this->overviewText('kpi_active_operations_tendency_none');
        }

        if ($count === 1) {
            return $this->overviewText('kpi_active_operations_tendency_one');
        }

        return $this->overviewText('kpi_active_operations_tendency', ['count' => $count]);
    }

    private function trendDirectionIcon(bool $hasAttention): string
    {
        return $hasAttention
            ? 'heroicon-m-arrow-trending-up'
            : 'heroicon-m-arrow-trending-down';
    }

    /**
     * @return list<int>|null
     */
    private function highSeverityFindingsChart(ManagedEnvironment $tenant): ?array
    {
        $window = $this->sevenDayWindow();
        $byDay = Finding::query()
            ->where('managed_environment_id', (int) $tenant->getKey())
            ->whereIn('severity', Finding::highSeverityValues())
            ->where(function (Builder $query) use ($window): void {
                $query
                    ->whereBetween('first_seen_at', [$window['start'], $window['end']])
                    ->orWhere(function (Builder $fallbackQuery) use ($window): void {
                        $fallbackQuery
                            ->whereNull('first_seen_at')
                            ->whereBetween('created_at', [$window['start'], $window['end']]);
                    });
            })
            ->selectRaw('date(coalesce(first_seen_at, created_at)) as chart_date, count(*) as aggregate')
            ->groupByRaw('date(coalesce(first_seen_at, created_at))')
            ->pluck('aggregate', 'chart_date')
            ->all();

        return $this->normalizeSevenDayChart($byDay, $window['start']);
    }

    /**
     * @return list<int>|null
     */
    private function operationsFollowUpChart(ManagedEnvironment $tenant): ?array
    {
        $window = $this->sevenDayWindow();
        $byDay = $this->operationsRequiringAttentionQuery($tenant)
            ->where(function (Builder $query) use ($window): void {
                $query
                    ->whereBetween('completed_at', [$window['start'], $window['end']])
                    ->orWhere(function (Builder $activeQuery) use ($window): void {
                        $activeQuery
                            ->whereNull('completed_at')
                            ->whereBetween('created_at', [$window['start'], $window['end']]);
                    });
            })
            ->selectRaw('date(coalesce(completed_at, created_at)) as chart_date, count(*) as aggregate')
            ->groupByRaw('date(coalesce(completed_at, created_at))')
            ->pluck('aggregate', 'chart_date')
            ->all();

        return $this->normalizeSevenDayChart($byDay, $window['start']);
    }

    /**
     * @return array{start: Carbon, end: Carbon}
     */
    private function sevenDayWindow(): array
    {
        $end = now()->endOfDay();

        return [
            'start' => $end->copy()->startOfDay()->subDays(6),
            'end' => $end,
        ];
    }

    /**
     * @param  array<string, int|string>  $byDay
     * @return list<int>|null
     */
    private function normalizeSevenDayChart(array $byDay, Carbon $windowStart): ?array
    {
        $series = [];

        for ($day = $windowStart->copy(); $day->lte(now()); $day->addDay()) {
            $series[] = (int) ($byDay[$day->toDateString()] ?? 0);
        }

        return array_sum($series) > 0 ? $series : null;
    }

    /**
     * @param  array<string, mixed>  $requiredPermissions
     * @param  array{active:int,expiring:int,expired:int,pending:int,total:int}  $exceptionStats
     * @return list<array<string, mixed>>
     */
    private function recommendedActions(
        ManagedEnvironment $tenant,
        ?User $user,
        TenantGovernanceAggregate $aggregate,
        TenantBackupHealthAssessment $backupHealth,
        array $recoveryEvidence,
        array $requiredPermissions,
        ?EnvironmentReview $latestReview,
        ?ReviewPack $latestReviewPack,
        array $exceptionStats,
    ): array {
        $counts = is_array($requiredPermissions['overview']['counts'] ?? null)
            ? $requiredPermissions['overview']['counts']
            : [];
        $overview = is_array($requiredPermissions['overview'] ?? null)
            ? $requiredPermissions['overview']
            : [];

        $candidates = [];

        $missingApplicationPermissions = (int) ($counts['missing_application'] ?? 0);
        $missingDelegatedPermissions = (int) ($counts['missing_delegated'] ?? 0);

        if ($missingApplicationPermissions > 0) {
            $candidates[] = $this->actionCandidate(
                priority: 10,
                key: 'required_permissions',
                title: $this->overviewText('action_review_permissions'),
                reason: $this->overviewText('reason_missing_application_permissions', ['count' => $missingApplicationPermissions]),
                impact: $this->overviewText('impact_missing_application_permissions'),
                tone: 'danger',
                action: $this->requiredPermissionsAction($tenant, $user, $this->overviewText('action_review_permissions')),
            );
        } elseif ($missingDelegatedPermissions > 0) {
            $candidates[] = $this->actionCandidate(
                priority: 20,
                key: 'delegated_permissions',
                title: $this->overviewText('action_review_permissions'),
                reason: $this->overviewText('reason_missing_delegated_permissions', ['count' => $missingDelegatedPermissions]),
                impact: $this->overviewText('impact_missing_delegated_permissions'),
                tone: 'warning',
                action: $this->requiredPermissionsAction($tenant, $user, $this->overviewText('action_review_permissions')),
            );
        }

        if ($aggregate->highSeverityActiveFindingsCount > 0) {
            $candidates[] = $this->actionCandidate(
                priority: 30,
                key: 'high_severity_findings',
                title: $this->overviewText('action_review_findings'),
                reason: $this->overviewText('reason_high_severity_findings', ['count' => $aggregate->highSeverityActiveFindingsCount]),
                impact: $this->overviewText('impact_high_severity_findings'),
                tone: 'danger',
                action: $this->tenantFindingsAction($tenant, $user, $this->overviewText('action_review_findings'), [
                    'tab' => 'needs_action',
                    'high_severity' => 1,
                ]),
            );
        }

        if ($aggregate->overdueOpenFindingsCount > 0) {
            $candidates[] = $this->actionCandidate(
                priority: 40,
                key: 'overdue_findings',
                title: $this->overviewText('action_review_findings'),
                reason: $this->overviewText('reason_overdue_findings', ['count' => $aggregate->overdueOpenFindingsCount]),
                impact: $this->overviewText('impact_overdue_findings'),
                tone: 'warning',
                action: $this->tenantFindingsAction($tenant, $user, $this->overviewText('action_open_overdue_findings'), [
                    'tab' => 'overdue',
                ]),
            );
        }

        $exceptionNeedsAction = $exceptionStats['pending'] + $exceptionStats['expiring'] + $exceptionStats['expired'];

        if ($exceptionNeedsAction > 0 || $aggregate->lapsedGovernanceCount > 0 || $aggregate->expiringGovernanceCount > 0) {
            $candidates[] = $this->actionCandidate(
                priority: 50,
                key: 'risk_exceptions',
                title: $this->overviewText('action_review_risks'),
                reason: $this->overviewText('reason_risk_exceptions', ['count' => max($exceptionNeedsAction, $aggregate->lapsedGovernanceCount + $aggregate->expiringGovernanceCount)]),
                impact: $this->overviewText('impact_risk_exceptions'),
                tone: $aggregate->lapsedGovernanceCount > 0 || $exceptionStats['expired'] > 0 ? 'danger' : 'warning',
                action: $this->riskExceptionsAction($tenant, $user, $this->overviewText('action_review_risks')),
            );
        }

        if ($backupHealth->posture !== TenantBackupHealthAssessment::POSTURE_HEALTHY || TenantRecoveryTriagePresentation::recoveryEvidenceState($recoveryEvidence) !== TenantRecoveryTriagePresentation::RECOVERY_EVIDENCE_NO_RECENT_ISSUES_VISIBLE) {
            $candidates[] = $this->actionCandidate(
                priority: 60,
                key: 'recovery_posture',
                title: $this->overviewText('action_review_recovery_posture'),
                reason: TenantRecoveryTriagePresentation::backupPostureDescription($backupHealth) ?? $backupHealth->headline,
                impact: $this->overviewText('impact_recovery_posture'),
                tone: $backupHealth->tone(),
                action: $this->backupHealthAction($tenant, $user, $this->overviewText('action_open_backup_posture'), $backupHealth),
            );
        }

        $operationsRequiringAttention = $this->operationsRequiringAttentionRuns($tenant);

        if ($operationsRequiringAttention->isNotEmpty()) {
            $dominantProblemClass = $this->dominantAttentionProblemClass($operationsRequiringAttention);

            $candidates[] = $this->actionCandidate(
                priority: 35,
                key: 'operations_requiring_attention',
                title: $this->overviewText('action_review_operations_requiring_attention'),
                reason: $this->overviewText('reason_operations_requiring_attention'),
                impact: $this->overviewText('impact_operations_requiring_attention'),
                tone: 'danger',
                action: $this->operationsAction(
                    tenant: $tenant,
                    user: $user,
                    label: $this->overviewText('action_review_operations'),
                    activeTab: $dominantProblemClass,
                    problemClass: $dominantProblemClass,
                ),
            );
        }

        if ($latestReview instanceof EnvironmentReview && $latestReviewPack?->status !== 'ready') {
            $candidates[] = $this->actionCandidate(
                priority: 80,
                key: 'continue_review',
                title: $this->overviewText('action_continue_review'),
                reason: $this->overviewText('reason_continue_review'),
                impact: $this->overviewText('impact_continue_review'),
                tone: 'info',
                action: $this->continueReviewAction($tenant, $user, $latestReview),
            );
        }

        return collect($candidates)
            ->sortBy('priority')
            ->take(3)
            ->values()
            ->all();
    }

    /**
     * @param  array<string, mixed>  $requiredPermissions
     * @return list<array<string, mixed>>
     */
    private function governanceStatus(
        ManagedEnvironment $tenant,
        ?User $user,
        TenantGovernanceAggregate $aggregate,
        TenantBackupHealthAssessment $backupHealth,
        array $requiredPermissions,
        ?EnvironmentReview $latestReview,
        ?EvidenceSnapshot $latestEvidenceSnapshot,
    ): array {
        $overview = is_array($requiredPermissions['overview'] ?? null)
            ? $requiredPermissions['overview']
            : [];
        $counts = is_array($overview['counts'] ?? null)
            ? $overview['counts']
            : [];
        $freshness = is_array($overview['freshness'] ?? null)
            ? $overview['freshness']
            : [];

        return [
            [
                'key' => 'baseline_compare',
                'label' => $this->overviewText('governance_baseline_compare_label'),
                'icon' => $this->governanceStatusIcon('baseline_compare'),
                'value' => $aggregate->headline,
                'tone' => $aggregate->tone,
                'description' => $aggregate->supportingMessage ?? $this->overviewText('governance_baseline_compare_description'),
                ...$this->baselineCompareAction($tenant, $user, $this->overviewText('action_open_baseline_compare')),
            ],
            [
                'key' => 'evidence_coverage',
                'label' => $this->overviewText('governance_evidence_coverage_label'),
                'icon' => $this->governanceStatusIcon('evidence_coverage'),
                'value' => $this->evidenceCoverageValue($latestEvidenceSnapshot),
                'tone' => $this->evidenceCoverageTone($latestEvidenceSnapshot),
                'description' => $this->evidenceCoverageDescription($latestEvidenceSnapshot),
                ...$this->evidenceAction($tenant, $user, $this->overviewText('action_open_evidence'), $latestEvidenceSnapshot),
            ],
            [
                'key' => 'review_freshness',
                'label' => $this->overviewText('governance_review_freshness_label'),
                'icon' => $this->governanceStatusIcon('review_freshness'),
                'value' => $this->reviewValue($latestReview),
                'tone' => $this->reviewTone($latestReview),
                'description' => $this->reviewDescription($latestReview),
                ...$this->environmentReviewAction($tenant, $user, $this->reviewSurfaceActionLabel($tenant, $user, $latestReview), $latestReview),
            ],
            [
                'key' => 'provider_permissions',
                'label' => $this->overviewText('governance_provider_permissions_label'),
                'icon' => $this->governanceStatusIcon('provider_permissions'),
                'value' => $this->providerPermissionsValue($overview),
                'tone' => $this->providerPermissionsTone($overview),
                'description' => $this->providerPermissionsDescription($counts, $freshness),
                ...$this->requiredPermissionsAction($tenant, $user, $this->overviewText('action_open_required_permissions')),
            ],
            [
                'key' => 'backup_posture',
                'label' => $this->overviewText('governance_backup_posture_label'),
                'icon' => $this->governanceStatusIcon('backup_posture'),
                'value' => TenantRecoveryTriagePresentation::backupPostureLabel($backupHealth),
                'tone' => $backupHealth->tone(),
                'description' => TenantRecoveryTriagePresentation::backupPostureDescription($backupHealth) ?? $this->overviewText('governance_backup_posture_unavailable_description'),
                ...$this->backupHealthAction($tenant, $user, $this->overviewText('action_open_backup_posture'), $backupHealth),
            ],
        ];
    }

    /**
     * @param  array<string, mixed>  $requiredPermissions
     * @param  array{active:int,expiring:int,expired:int,pending:int,total:int}  $exceptionStats
     * @return list<array<string, mixed>>
     */
    private function readinessCards(
        ManagedEnvironment $tenant,
        ?User $user,
        ?ProviderConnection $primaryProviderConnection,
        array $requiredPermissions,
        ?EnvironmentReview $latestReview,
        ?ReviewPack $latestReviewPack,
        ?EvidenceSnapshot $latestEvidenceSnapshot,
        array $exceptionStats,
    ): array {
        return [
            $this->currentReviewCard($tenant, $user, $latestReview),
            $this->riskExceptionsCard($tenant, $user, $exceptionStats),
            $this->providerHealthCard($tenant, $user, $primaryProviderConnection, $requiredPermissions),
            $this->customerSafeOutputCard($tenant, $user, $latestReviewPack, $latestEvidenceSnapshot),
        ];
    }

    /**
     * @return array<string, mixed>
     */
    private function currentReviewCard(ManagedEnvironment $tenant, ?User $user, ?EnvironmentReview $latestReview): array
    {
        $timestamp = $latestReview?->published_at ?? $latestReview?->generated_at ?? $latestReview?->updated_at;

        return [
            'key' => 'current_review',
            'title' => $this->overviewText('readiness_current_review_title'),
            'status' => $latestReview instanceof EnvironmentReview
                ? $this->reviewValue($latestReview)
                : $this->overviewText('readiness_current_review_empty_status'),
            'tone' => $latestReview instanceof EnvironmentReview ? $this->reviewTone($latestReview) : 'gray',
            'body' => $latestReview instanceof EnvironmentReview
                ? $this->reviewDescription($latestReview)
                : $this->overviewText('readiness_current_review_empty_description'),
            'progress' => $this->reviewProgress($latestReview),
            'meta' => $this->cardMeta(
                $this->metaItem(
                    $this->overviewText('readiness_current_review_updated_label'),
                    $this->relativeTime($timestamp),
                ),
            ),
            ...$this->environmentReviewAction($tenant, $user, $this->reviewSurfaceActionLabel($tenant, $user, $latestReview), $latestReview),
        ];
    }

    /**
     * @param  array{active:int,expiring:int,expired:int,pending:int,total:int}  $exceptionStats
     * @return array<string, mixed>
     */
    private function riskExceptionsCard(ManagedEnvironment $tenant, ?User $user, array $exceptionStats): array
    {
        return [
            'key' => 'risk_exceptions',
            'title' => $this->overviewText('readiness_risk_exceptions_title'),
            'status' => $this->riskExceptionValue($exceptionStats),
            'tone' => $this->riskExceptionTone($exceptionStats),
            'body' => $this->riskExceptionDescription($exceptionStats),
            'meta' => $this->cardMeta(
                $this->metaItem($this->overviewText('readiness_risk_exceptions_active_label'), (string) $exceptionStats['active']),
                $this->metaItem($this->overviewText('readiness_risk_exceptions_expiring_label'), (string) $exceptionStats['expiring']),
                $this->metaItem($this->overviewText('readiness_risk_exceptions_pending_label'), (string) $exceptionStats['pending']),
            ),
            ...$this->riskExceptionsAction($tenant, $user, $this->overviewText('action_review_risks')),
        ];
    }

    /**
     * @param  array<string, mixed>  $requiredPermissions
     * @return array<string, mixed>
     */
    private function providerHealthCard(
        ManagedEnvironment $tenant,
        ?User $user,
        ?ProviderConnection $primaryProviderConnection,
        array $requiredPermissions,
    ): array {
        $overview = is_array($requiredPermissions['overview'] ?? null) ? $requiredPermissions['overview'] : [];
        $counts = is_array($overview['counts'] ?? null) ? $overview['counts'] : [];
        $freshness = is_array($overview['freshness'] ?? null) ? $overview['freshness'] : [];

        return [
            'key' => 'provider_health',
            'title' => $this->overviewText('readiness_provider_health_title'),
            'headline' => $this->providerHealthHeadline($primaryProviderConnection),
            'status' => $this->providerHealthStatus($primaryProviderConnection),
            'tone' => $this->providerHealthTone($primaryProviderConnection),
            'body' => $this->providerHealthDescription($primaryProviderConnection, $counts, $freshness),
            'meta' => $this->cardMeta(
                $this->metaItem(
                    $this->overviewText('readiness_provider_health_permissions_label'),
                    (string) ((int) ($counts['missing_application'] ?? 0) + (int) ($counts['missing_delegated'] ?? 0)),
                ),
                $this->metaItem(
                    $this->overviewText('readiness_provider_health_last_check_label'),
                    $this->relativeTime($primaryProviderConnection?->last_health_check_at),
                ),
                $this->metaItem(
                    $this->overviewText('readiness_provider_health_snapshot_label'),
                    $this->relativeTimeFromString($freshness['last_refreshed_at'] ?? null),
                ),
            ),
            ...$this->requiredPermissionsAction($tenant, $user, $this->overviewText('action_open_required_permissions')),
        ];
    }

    /**
     * @return array<string, mixed>
     */
    private function customerSafeOutputCard(
        ManagedEnvironment $tenant,
        ?User $user,
        ?ReviewPack $latestReviewPack,
        ?EvidenceSnapshot $latestEvidenceSnapshot,
    ): array {
        return [
            'key' => 'customer_safe_output',
            'title' => $this->overviewText('readiness_customer_safe_output_title'),
            'status' => $this->customerSafeOutputStatus($latestReviewPack, $latestEvidenceSnapshot),
            'tone' => $this->customerSafeOutputTone($latestReviewPack, $latestEvidenceSnapshot),
            'body' => $this->customerSafeOutputDescription($latestReviewPack, $latestEvidenceSnapshot),
            'meta' => $this->cardMeta(
                $this->metaItem(
                    $this->overviewText('readiness_customer_safe_output_evidence_label'),
                    $this->relativeTime($latestEvidenceSnapshot?->generated_at) ?? $this->overviewText('status_unavailable'),
                ),
                $this->metaItem(
                    $this->overviewText('readiness_customer_safe_output_review_pack_label'),
                    $this->relativeTime($latestReviewPack?->generated_at) ?? $this->overviewText('status_unavailable'),
                ),
            ),
            ...$this->customerWorkspaceAction($tenant, $user, $latestReviewPack),
        ];
    }

    /**
     * @param  list<OperationRun>  $recentOperations
     * @return list<array<string, mixed>>
     */
    private function recentOperationCards(ManagedEnvironment $tenant, array $recentOperations): array
    {
        return collect($recentOperations)
            ->map(function (OperationRun $operation) use ($tenant): array {
                $statusSpec = BadgeRenderer::spec(BadgeDomain::OperationRunStatus, [
                    'status' => (string) $operation->status,
                    'freshness_state' => $operation->freshnessState()->value,
                ]);
                $outcomeSpec = BadgeRenderer::spec(BadgeDomain::OperationRunOutcome, [
                    'outcome' => (string) $operation->outcome,
                    'status' => (string) $operation->status,
                    'freshness_state' => $operation->freshnessState()->value,
                ]);

                return [
                    'id' => (int) $operation->getKey(),
                    'identifier' => OperationRunLinks::identifier($operation),
                    'type' => OperationCatalog::label((string) $operation->type),
                    'icon' => $this->recentOperationIcon((string) $operation->type),
                    'statusLabel' => $statusSpec->label,
                    'statusTone' => $statusSpec->color,
                    'outcomeLabel' => $outcomeSpec->label,
                    'outcomeTone' => $outcomeSpec->color,
                    'summary' => OperationUxPresenter::lifecycleAttentionSummary($operation)
                        ?? OperationUxPresenter::surfaceGuidance($operation)
                        ?? $this->overviewText('recent_operation_fallback_summary'),
                    'url' => OperationRunLinks::view($operation, $tenant),
                    'createdAt' => $operation->created_at?->diffForHumans(),
                ];
            })
            ->values()
            ->all();
    }

    /**
     * @return array<string, mixed>|null
     */
    private function activeOperationSummary(ManagedEnvironment $tenant, ?User $user): ?array
    {
        if (! $user instanceof User || ! $user->canAccessTenant($tenant)) {
            return null;
        }

        $qualifyingRuns = $this->operationsRequiringAttentionRuns($tenant);

        if ($qualifyingRuns->isEmpty()) {
            return null;
        }

        $dominantProblemClass = $this->dominantAttentionProblemClass($qualifyingRuns);

        return [
            'title' => $this->overviewText('operations_attention_title'),
            'count' => $qualifyingRuns->count(),
            'tone' => 'warning',
            'secondaryActionLabel' => $this->overviewText('action_open_operations_hub'),
            'secondaryActionUrl' => OperationRunLinks::index(
                $tenant,
                activeTab: $dominantProblemClass,
                problemClass: $dominantProblemClass,
            ),
            'items' => $this->attentionOperationItems($qualifyingRuns, $tenant),
        ];
    }

    private function compareActiveOperationSummaryRuns(OperationRun $left, OperationRun $right): int
    {
        $priorityComparison = $this->activeOperationSummaryPriority($left) <=> $this->activeOperationSummaryPriority($right);

        if ($priorityComparison !== 0) {
            return $priorityComparison;
        }

        $timestampComparison = $this->activeOperationSummaryTimestamp($right) <=> $this->activeOperationSummaryTimestamp($left);

        if ($timestampComparison !== 0) {
            return $timestampComparison;
        }

        return ((int) $right->getKey()) <=> ((int) $left->getKey());
    }

    private function activeOperationSummaryPriority(OperationRun $run): int
    {
        return match ($run->problemClass()) {
            OperationRun::PROBLEM_CLASS_TERMINAL_FOLLOW_UP => 0,
            OperationRun::PROBLEM_CLASS_ACTIVE_STALE_ATTENTION => 1,
            default => 2,
        };
    }

    private function activeOperationSummaryTimestamp(OperationRun $run): int
    {
        return ($run->completed_at ?? $run->started_at ?? $run->created_at)?->getTimestamp() ?? 0;
    }

    private function governanceStatusIcon(string $key): string
    {
        return match ($key) {
            'baseline_compare' => 'heroicon-m-arrows-right-left',
            'evidence_coverage' => 'heroicon-m-document-check',
            'review_freshness' => 'heroicon-m-clipboard-document-check',
            'provider_permissions' => 'heroicon-m-key',
            'backup_posture' => 'heroicon-m-archive-box',
            default => 'heroicon-m-arrow-path-rounded-square',
        };
    }

    private function recentOperationIcon(string $operationType): string
    {
        return match (OperationCatalog::canonicalCode($operationType)) {
            'inventory.sync' => 'heroicon-m-arrow-path',
            'environment.review_pack.generate' => 'heroicon-m-document-arrow-down',
            'environment.review.compose' => 'heroicon-m-document-text',
            'tenant.evidence.snapshot.generate' => 'heroicon-m-document-duplicate',
            'baseline.compare' => 'heroicon-m-arrows-right-left',
            'provider.connection.check', 'rbac.health_check' => 'heroicon-m-shield-check',
            'permission.posture.check' => 'heroicon-m-key',
            default => 'heroicon-m-arrow-path-rounded-square',
        };
    }

    /**
     * @param  array<string, mixed>  $action
     * @return array<string, mixed>
     */
    private function metricCard(
        string $key,
        string $label,
        int $value,
        string $description,
        string $tone,
        string $icon,
        array $action,
        ?array $chart = null,
    ): array {
        return array_merge([
            'key' => $key,
            'label' => $label,
            'value' => $value,
            'description' => $description,
            'tone' => $tone,
            'icon' => $icon,
            'chart' => $chart,
        ], $action);
    }

    /**
     * @param  array<string, mixed>  $action
     * @return array<string, mixed>
     */
    private function actionCandidate(int $priority, string $key, string $title, string $reason, string $impact, string $tone, array $action): array
    {
        return array_merge([
            'priority' => $priority,
            'key' => $key,
            'icon' => $this->recommendedActionIcon($key),
            'title' => $title,
            'reason' => $reason,
            'impact' => $impact,
            'tone' => $tone,
        ], $action);
    }

    private function recommendedActionIcon(string $key): string
    {
        return match ($key) {
            'required_permissions', 'delegated_permissions', 'high_severity_findings' => 'heroicon-m-shield-exclamation',
            'overdue_findings' => 'heroicon-o-clock',
            'recovery_posture', 'operations_requiring_attention', 'continue_review' => 'heroicon-o-arrow-path-rounded-square',
            'risk_exceptions' => 'heroicon-o-exclamation-triangle',
            default => 'heroicon-o-exclamation-triangle',
        };
    }

    /**
     * @param  array<string, mixed>  $parameters
     * @return array{actionLabel:string,actionUrl:?string,actionDisabled:bool,helperText:?string}
     */
    private function tenantFindingsAction(ManagedEnvironment $tenant, ?User $user, string $label, array $parameters = []): array
    {
        $canOpen = $this->canOpenTenantCapability($tenant, $user, Capabilities::TENANT_FINDINGS_VIEW);

        return $this->actionPayload(
            label: $label,
            url: $canOpen ? FindingResource::getUrl('index', $parameters, tenant: $tenant) : null,
            helperText: $canOpen ? null : $this->overviewText('helper_findings_requires_permissions'),
        );
    }

    /**
     * @return array{actionLabel:string,actionUrl:?string,actionDisabled:bool,helperText:?string}
     */
    private function riskExceptionsAction(ManagedEnvironment $tenant, ?User $user, string $label): array
    {
        $canOpen = $this->canOpenTenantCapability($tenant, $user, Capabilities::FINDING_EXCEPTION_VIEW);

        return $this->actionPayload(
            label: $label,
            url: $canOpen ? FindingExceptionResource::getUrl('index', tenant: $tenant) : null,
            helperText: $canOpen ? null : $this->overviewText('helper_risk_exceptions_requires_permissions'),
        );
    }

    /**
     * @return array{actionLabel:string,actionUrl:?string,actionDisabled:bool,helperText:?string}
     */
    private function environmentReviewAction(ManagedEnvironment $tenant, ?User $user, string $label, ?EnvironmentReview $review = null): array
    {
        $canOpen = $this->canOpenTenantCapability($tenant, $user, Capabilities::ENVIRONMENT_REVIEW_VIEW);

        $url = null;

        if ($canOpen) {
            $url = $review instanceof EnvironmentReview
                ? EnvironmentReviewResource::environmentScopedUrl('view', ['record' => $review], $tenant)
                : EnvironmentReviewResource::environmentScopedUrl('index', tenant: $tenant);
        }

        return $this->actionPayload(
            label: $label,
            url: $url,
            helperText: $canOpen ? null : $this->overviewText('helper_review_requires_permissions'),
        );
    }

    /**
     * @return array{actionLabel:string,actionUrl:?string,actionDisabled:bool,helperText:?string}
     */
    private function continueReviewAction(ManagedEnvironment $tenant, ?User $user, EnvironmentReview $review): array
    {
        $canContinue = $this->canOpenTenantCapability($tenant, $user, Capabilities::ENVIRONMENT_REVIEW_MANAGE);

        return $this->actionPayload(
            label: $this->overviewText('action_continue_review'),
            url: $canContinue ? EnvironmentReviewResource::environmentScopedUrl('view', ['record' => $review], $tenant) : null,
            helperText: $canContinue ? null : $this->overviewText('helper_continue_review_requires_manage'),
        );
    }

    /**
     * @return array{actionLabel:string,actionUrl:?string,actionDisabled:bool,helperText:?string}
     */
    private function evidenceAction(ManagedEnvironment $tenant, ?User $user, string $label, ?EvidenceSnapshot $snapshot = null): array
    {
        $canOpen = $this->canOpenTenantCapability($tenant, $user, Capabilities::EVIDENCE_VIEW);

        $url = null;

        if ($canOpen) {
            $url = $snapshot instanceof EvidenceSnapshot
                ? EvidenceSnapshotResource::getUrl('view', ['record' => $snapshot], tenant: $tenant)
                : EvidenceSnapshotResource::getUrl('index', tenant: $tenant);
        }

        return $this->actionPayload(
            label: $label,
            url: $url,
            helperText: $canOpen ? null : $this->overviewText('helper_evidence_requires_permissions'),
        );
    }

    /**
     * @return array{actionLabel:string,actionUrl:?string,actionDisabled:bool,helperText:?string}
     */
    private function customerWorkspaceAction(ManagedEnvironment $tenant, ?User $user, ?ReviewPack $reviewPack): array
    {
        $canOpenWorkspace = $user instanceof User
            && $user->canAccessTenant($tenant)
            && (
                $user->can(Capabilities::ENVIRONMENT_REVIEW_VIEW, $tenant)
                || $user->can(Capabilities::REVIEW_PACK_VIEW, $tenant)
                || $user->can(Capabilities::EVIDENCE_VIEW, $tenant)
            );

        $label = $reviewPack instanceof ReviewPack && (string) $reviewPack->status === 'ready'
            ? $this->overviewText('action_open_review_pack')
            : $this->overviewText('action_view_export_artifacts');

        $url = null;

        if ($canOpenWorkspace) {
            $url = $reviewPack instanceof ReviewPack && $user->can(Capabilities::REVIEW_PACK_VIEW, $tenant)
                ? ReviewPackResource::getUrl('view', ['record' => $reviewPack], tenant: $tenant)
                : CustomerReviewWorkspace::environmentFilterUrl($tenant);
        }

        return $this->actionPayload(
            label: $label,
            url: $url,
            helperText: $canOpenWorkspace ? null : $this->overviewText('helper_customer_workspace_requires_permissions'),
        );
    }

    /**
     * @return array{actionLabel:string,actionUrl:?string,actionDisabled:bool,helperText:?string}
     */
    private function requiredPermissionsAction(ManagedEnvironment $tenant, ?User $user, string $label): array
    {
        $canOpen = $user instanceof User && $user->canAccessTenant($tenant);

        return $this->actionPayload(
            label: $label,
            url: $canOpen ? RequiredPermissionsLinks::requiredPermissions($tenant) : null,
            helperText: $canOpen ? null : $this->overviewText('helper_required_permissions_unavailable'),
        );
    }

    /**
     * @return array{actionLabel:string,actionUrl:?string,actionDisabled:bool,helperText:?string}
     */
    private function operationsAction(ManagedEnvironment $tenant, ?User $user, string $label, ?string $activeTab = null, ?string $problemClass = null): array
    {
        $canOpen = $user instanceof User && $user->canAccessTenant($tenant);

        return $this->actionPayload(
            label: $label,
            url: $canOpen ? OperationRunLinks::index($tenant, activeTab: $activeTab, problemClass: $problemClass) : null,
            helperText: $canOpen ? null : $this->overviewText('helper_operations_unavailable'),
        );
    }

    private function operationsRequiringAttentionQuery(ManagedEnvironment $tenant): Builder
    {
        return OperationRun::query()
            ->where('managed_environment_id', (int) $tenant->getKey())
            ->where('workspace_id', (int) $tenant->workspace_id)
            ->dashboardNeedsFollowUp();
    }

    /**
     * @return Collection<int, OperationRun>
     */
    private function operationsRequiringAttentionRuns(ManagedEnvironment $tenant): Collection
    {
        return $this->operationsRequiringAttentionQuery($tenant)
            ->get()
            ->sort(fn (OperationRun $left, OperationRun $right): int => $this->compareActiveOperationSummaryRuns($left, $right))
            ->values();
    }

    /**
     * @param  Collection<int, OperationRun>  $runs
     * @return list<array<string, mixed>>
     */
    private function attentionOperationItems(Collection $runs, ManagedEnvironment $tenant): array
    {
        return $runs
            ->take(3)
            ->map(function (OperationRun $run) use ($tenant): array {
                $statusSpec = BadgeRenderer::spec(BadgeDomain::OperationRunStatus, [
                    'status' => (string) $run->status,
                    'freshness_state' => $run->freshnessState()->value,
                ]);
                $outcomeSpec = BadgeRenderer::spec(BadgeDomain::OperationRunOutcome, [
                    'outcome' => (string) $run->outcome,
                    'status' => (string) $run->status,
                    'freshness_state' => $run->freshnessState()->value,
                ]);

                return [
                    'id' => (int) $run->getKey(),
                    'identifier' => OperationRunLinks::identifier($run),
                    'type' => OperationCatalog::label((string) $run->type),
                    'title' => $this->attentionOperationTitle($run),
                    'icon' => $this->recentOperationIcon((string) $run->type),
                    'attentionLabel' => $this->attentionOperationBadgeLabel($run),
                    'problemClass' => $run->problemClass(),
                    'problemClassLabel' => OperationUxPresenter::problemClassLabel($run),
                    'statusLabel' => $statusSpec->label,
                    'statusTone' => $statusSpec->color,
                    'outcomeLabel' => $outcomeSpec->label,
                    'outcomeTone' => $outcomeSpec->color,
                    'outcomeSentence' => $this->attentionOperationOutcomeSentence($run),
                    'reason' => $this->attentionOperationReason($run),
                    'impact' => $this->attentionOperationImpact($run),
                    'timingLabel' => $this->attentionOperationTimingLabel($run),
                    'createdAt' => $run->completed_at?->diffForHumans() ?? $run->created_at?->diffForHumans(),
                    'primaryActionLabel' => $this->overviewText('action_review_operation'),
                    'primaryActionUrl' => OperationRunLinks::view($run, $tenant),
                ];
            })
            ->values()
            ->all();
    }

    /**
     * @param  Collection<int, OperationRun>  $runs
     */
    private function dominantAttentionProblemClass(Collection $runs): string
    {
        return $runs->contains(fn (OperationRun $run): bool => $run->problemClass() === OperationRun::PROBLEM_CLASS_TERMINAL_FOLLOW_UP)
            ? OperationRun::PROBLEM_CLASS_TERMINAL_FOLLOW_UP
            : OperationRun::PROBLEM_CLASS_ACTIVE_STALE_ATTENTION;
    }

    private function attentionOperationTitle(OperationRun $run): string
    {
        return OperationCatalog::label((string) $run->type);
    }

    private function attentionOperationBadgeLabel(OperationRun $run): string
    {
        return $run->problemClass() === OperationRun::PROBLEM_CLASS_ACTIVE_STALE_ATTENTION
            ? $this->overviewText('operations_attention_badge_stale')
            : $this->overviewText('operations_attention_badge_follow_up');
    }

    private function attentionOperationOutcomeSentence(OperationRun $run): string
    {
        if ($run->problemClass() === OperationRun::PROBLEM_CLASS_ACTIVE_STALE_ATTENTION) {
            return $this->overviewText('operations_attention_outcome_stale');
        }

        if ($this->isProviderConsentBlockedRun($run)) {
            return $this->overviewText('operations_attention_outcome_provider_consent_required');
        }

        return match ((string) $run->outcome) {
            OperationRunOutcome::Blocked->value => $this->overviewText('operations_attention_outcome_blocked'),
            OperationRunOutcome::PartiallySucceeded->value => $this->overviewText('operations_attention_outcome_partial'),
            OperationRunOutcome::Failed->value => $this->overviewText('operations_attention_outcome_failed'),
            default => $this->overviewText('operations_attention_outcome_generic'),
        };
    }

    private function attentionOperationReason(OperationRun $run): string
    {
        if ($this->isProviderConsentBlockedRun($run)) {
            return $this->overviewText('operations_attention_reason_provider_consent_required');
        }

        $operatorExplanation = OperationUxPresenter::governanceOperatorExplanation($run);
        $reason = trim((string) ($operatorExplanation?->dominantCauseExplanation ?? ''));

        if ($reason !== '') {
            return $reason;
        }

        $failureDetail = trim((string) (OperationUxPresenter::surfaceFailureDetail($run) ?? ''));

        if ($failureDetail !== '') {
            return $failureDetail;
        }

        return $run->problemClass() === OperationRun::PROBLEM_CLASS_ACTIVE_STALE_ATTENTION
            ? $this->overviewText('operations_attention_reason_stale')
            : $this->overviewText('operations_attention_reason_fallback');
    }

    private function attentionOperationImpact(OperationRun $run): string
    {
        if ($this->isProviderConsentBlockedRun($run)) {
            return $this->overviewText('operations_attention_impact_provider_consent_required');
        }

        return $run->problemClass() === OperationRun::PROBLEM_CLASS_ACTIVE_STALE_ATTENTION
            ? $this->overviewText('operations_attention_impact_stale')
            : $this->overviewText('operations_attention_impact_follow_up');
    }

    private function attentionOperationTimingLabel(OperationRun $run): ?string
    {
        if ($run->completed_at instanceof Carbon) {
            return $this->overviewText('operations_attention_timing_completed', [
                'time' => $run->completed_at->diffForHumans(),
            ]);
        }

        $reference = $run->started_at ?? $run->created_at;

        if (! $reference instanceof Carbon) {
            return null;
        }

        return $this->overviewText('operations_attention_timing_started', [
            'time' => $reference->diffForHumans(),
        ]);
    }

    private function isProviderConsentBlockedRun(OperationRun $run): bool
    {
        return OperationCatalog::canonicalCode((string) $run->type) === OperationCatalog::TYPE_PERMISSION_POSTURE_CHECK
            && (string) $run->outcome === OperationRunOutcome::Blocked->value;
    }

    /**
     * @return array{actionLabel:string,actionUrl:?string,actionDisabled:bool,helperText:?string}
     */
    private function baselineCompareAction(ManagedEnvironment $tenant, ?User $user, string $label): array
    {
        $canOpen = $this->canOpenTenantCapability($tenant, $user, Capabilities::TENANT_VIEW);

        return $this->actionPayload(
            label: $label,
            url: $canOpen ? ManagedEnvironmentLinks::baselineCompareUrl($tenant) : null,
            helperText: $canOpen ? null : $this->overviewText('helper_baseline_compare_requires_permissions'),
        );
    }

    /**
     * @return array{actionLabel:string,actionUrl:?string,actionDisabled:bool,helperText:?string}
     */
    private function backupHealthAction(ManagedEnvironment $tenant, ?User $user, string $label, TenantBackupHealthAssessment $backupHealth): array
    {
        $canOpen = $this->canOpenTenantCapability($tenant, $user, Capabilities::TENANT_VIEW);

        if (! $canOpen) {
            return $this->actionPayload(
                label: $label,
                url: null,
                helperText: $this->overviewText('helper_backup_posture_requires_permissions'),
            );
        }

        $target = $backupHealth->primaryActionTarget;

        if (! $target instanceof BackupHealthActionTarget) {
            return $this->actionPayload(label: $label, url: null, helperText: null);
        }

        $url = match ($target->surface) {
            BackupHealthActionTarget::SURFACE_BACKUP_SET_VIEW => $target->recordId !== null
                ? BackupSetResource::getUrl('view', ['record' => $target->recordId], tenant: $tenant)
                : BackupSetResource::getUrl('index', tenant: $tenant),
            BackupHealthActionTarget::SURFACE_BACKUP_SETS_INDEX => BackupSetResource::getUrl('index', tenant: $tenant),
            BackupHealthActionTarget::SURFACE_BACKUP_SCHEDULES_INDEX => BackupScheduleResource::getUrl('index', tenant: $tenant),
            default => null,
        };

        return $this->actionPayload(
            label: $label,
            url: $url,
            helperText: $url === null ? null : null,
        );
    }

    /**
     * @return array{actionLabel:string,actionUrl:?string,actionDisabled:bool,helperText:?string}
     */
    private function actionPayload(string $label, ?string $url, ?string $helperText): array
    {
        return [
            'actionLabel' => $label,
            'actionUrl' => $url,
            'actionDisabled' => $url === null && $helperText !== null,
            'helperText' => $helperText,
        ];
    }

    private function canOpenTenantCapability(ManagedEnvironment $tenant, ?User $user, string $capability): bool
    {
        return $user instanceof User
            && $user->canAccessTenant($tenant)
            && $user->can($capability, $tenant);
    }

    private function reviewSurfaceActionLabel(ManagedEnvironment $tenant, ?User $user, ?EnvironmentReview $review): string
    {
        if (! $review instanceof EnvironmentReview) {
            return $this->overviewText('action_open_reviews');
        }

        return $this->canOpenTenantCapability($tenant, $user, Capabilities::ENVIRONMENT_REVIEW_MANAGE)
            ? $this->overviewText('action_continue_review')
            : $this->overviewText('action_open_review');
    }

    private function evidenceCoverageValue(?EvidenceSnapshot $snapshot): string
    {
        if (! $snapshot instanceof EvidenceSnapshot) {
            return $this->overviewText('status_unavailable');
        }

        return BadgeRenderer::spec(BadgeDomain::EvidenceCompleteness, (string) $snapshot->completeness_state)->label;
    }

    private function evidenceCoverageTone(?EvidenceSnapshot $snapshot): string
    {
        if (! $snapshot instanceof EvidenceSnapshot) {
            return 'warning';
        }

        return BadgeRenderer::spec(BadgeDomain::EvidenceCompleteness, (string) $snapshot->completeness_state)->color;
    }

    private function evidenceCoverageDescription(?EvidenceSnapshot $snapshot): string
    {
        if (! $snapshot instanceof EvidenceSnapshot) {
            return $this->overviewText('evidence_unavailable_description');
        }

        return $this->overviewText('evidence_generated_prefix', ['time' => $snapshot->generated_at?->diffForHumans()]);
    }

    private function reviewValue(?EnvironmentReview $review): string
    {
        if (! $review instanceof EnvironmentReview) {
            return $this->overviewText('status_not_ready');
        }

        return BadgeRenderer::spec(BadgeDomain::EnvironmentReviewStatus, (string) $review->status)->label;
    }

    private function reviewTone(?EnvironmentReview $review): string
    {
        if (! $review instanceof EnvironmentReview) {
            return 'warning';
        }

        return BadgeRenderer::spec(BadgeDomain::EnvironmentReviewStatus, (string) $review->status)->color;
    }

    private function reviewDescription(?EnvironmentReview $review): string
    {
        if (! $review instanceof EnvironmentReview) {
            return $this->overviewText('review_unavailable_description');
        }

        $timestamp = $review->published_at ?? $review->generated_at;

        return $this->overviewText('review_updated_prefix', ['time' => $timestamp?->diffForHumans()]);
    }

    /**
     * @return list<array<string, int|string>>
     */
    private function reviewProgress(?EnvironmentReview $review): array
    {
        if (! $review instanceof EnvironmentReview) {
            return [];
        }

        $summary = is_array($review->summary) ? $review->summary : [];
        $progress = [];

        $findingsProgress = $this->reviewFindingsProgress($summary);

        if ($findingsProgress !== null) {
            $progress[] = $findingsProgress;
        }

        $completionProgress = $this->reviewCompletionProgress($summary);

        if ($completionProgress !== null) {
            $progress[] = $completionProgress;
        }

        return $progress;
    }

    /**
     * @param  array<string, mixed>  $summary
     * @return array<string, int|string>|null
     */
    private function reviewFindingsProgress(array $summary): ?array
    {
        $findingCount = (int) ($summary['finding_count'] ?? 0);
        $reportBuckets = is_array($summary['finding_report_buckets'] ?? null)
            ? $summary['finding_report_buckets']
            : null;

        if ($findingCount <= 0 || $reportBuckets === null) {
            return null;
        }

        $reviewedCount = min(
            $findingCount,
            max(0, array_sum(array_map(static fn (mixed $count): int => max(0, (int) $count), $reportBuckets))),
        );

        return $this->progressItem(
            key: 'findings_with_outcome',
            label: $this->overviewText('readiness_current_review_findings_progress_label'),
            current: $reviewedCount,
            total: $findingCount,
            tone: $reviewedCount === $findingCount ? 'success' : 'primary',
        );
    }

    /**
     * @param  array<string, mixed>  $summary
     * @return array<string, int|string>|null
     */
    private function reviewCompletionProgress(array $summary): ?array
    {
        $sectionCount = (int) ($summary['section_count'] ?? 0);
        $sectionStateCounts = is_array($summary['section_state_counts'] ?? null)
            ? $summary['section_state_counts']
            : null;

        if ($sectionCount <= 0 || $sectionStateCounts === null) {
            return null;
        }

        $completeCount = min(
            $sectionCount,
            max(0, (int) ($sectionStateCounts['complete'] ?? 0)),
        );

        return $this->progressItem(
            key: 'review_completion',
            label: $this->overviewText('readiness_current_review_completion_progress_label'),
            current: $completeCount,
            total: $sectionCount,
            tone: $completeCount === $sectionCount ? 'success' : 'warning',
        );
    }

    /**
     * @return array{key:string,label:string,current:int,total:int,percent:int,valueLabel:string,tone:string}
     */
    private function progressItem(string $key, string $label, int $current, int $total, string $tone = 'primary'): array
    {
        $current = min($total, max(0, $current));
        $percent = (int) round(($current / $total) * 100);

        return [
            'key' => $key,
            'label' => $label,
            'current' => $current,
            'total' => $total,
            'percent' => $percent,
            'valueLabel' => sprintf('%d/%d (%d%%)', $current, $total, $percent),
            'tone' => $tone,
        ];
    }

    private function providerHealthHeadline(?ProviderConnection $connection): ?string
    {
        if (! $connection instanceof ProviderConnection) {
            return null;
        }

        $displayName = trim((string) ($connection->display_name ?? ''));

        if ($displayName !== '') {
            return $displayName;
        }

        if ($this->providerChipKey($connection) === 'microsoft') {
            return 'Microsoft Graph';
        }

        return $this->providerChipLabel($connection);
    }

    private function providerHealthStatus(?ProviderConnection $connection): string
    {
        if (! $connection instanceof ProviderConnection) {
            return $this->overviewText('readiness_provider_health_empty_status');
        }

        return BadgeRenderer::spec(BadgeDomain::ProviderVerificationStatus, $connection->verification_status)->label;
    }

    private function providerHealthTone(?ProviderConnection $connection): string
    {
        if (! $connection instanceof ProviderConnection) {
            return 'gray';
        }

        return BadgeRenderer::spec(BadgeDomain::ProviderVerificationStatus, $connection->verification_status)->color;
    }

    /**
     * @param  array<string, mixed>  $counts
     * @param  array<string, mixed>  $freshness
     */
    private function providerHealthDescription(?ProviderConnection $connection, array $counts, array $freshness): string
    {
        if (! $connection instanceof ProviderConnection) {
            return $this->overviewText('readiness_provider_health_empty_description');
        }

        $missingApplication = (int) ($counts['missing_application'] ?? 0);
        $missingDelegated = (int) ($counts['missing_delegated'] ?? 0);

        if ($missingApplication > 0 || $missingDelegated > 0 || ($freshness['is_stale'] ?? false) === true) {
            return $this->providerPermissionsDescription($counts, $freshness);
        }

        return match ($this->providerHealthState($connection)) {
            'healthy' => $this->overviewText('provider_permissions_complete_description'),
            'degraded' => $this->overviewText('readiness_provider_health_degraded_description'),
            'blocked' => $this->overviewText('readiness_provider_health_blocked_description'),
            'error' => $this->overviewText('readiness_provider_health_error_description'),
            'pending' => $this->overviewText('readiness_provider_health_pending_description'),
            default => $this->overviewText('readiness_provider_health_unknown_description'),
        };
    }

    /**
     * @param  array<string, mixed>  $overview
     */
    private function providerPermissionsValue(array $overview): string
    {
        return match ((string) ($overview['overall'] ?? VerificationReportOverall::NeedsAttention->value)) {
            VerificationReportOverall::Ready->value => $this->overviewText('provider_permissions_ready'),
            VerificationReportOverall::Blocked->value => $this->overviewText('provider_permissions_blocked'),
            default => $this->overviewText('provider_permissions_needs_attention'),
        };
    }

    /**
     * @param  array<string, mixed>  $overview
     */
    private function providerPermissionsTone(array $overview): string
    {
        return match ((string) ($overview['overall'] ?? 'needs_attention')) {
            VerificationReportOverall::Blocked->value => 'danger',
            VerificationReportOverall::Ready->value => 'success',
            default => 'warning',
        };
    }

    /**
     * @param  array<string, mixed>  $counts
     * @param  array<string, mixed>  $freshness
     */
    private function providerPermissionsDescription(array $counts, array $freshness): string
    {
        $missingApplication = (int) ($counts['missing_application'] ?? 0);
        $missingDelegated = (int) ($counts['missing_delegated'] ?? 0);

        $summary = match (true) {
            $missingApplication > 0 => $this->overviewText('reason_missing_application_permissions', ['count' => $missingApplication]),
            $missingDelegated > 0 => $this->overviewText('reason_missing_delegated_permissions', ['count' => $missingDelegated]),
            default => $this->overviewText('provider_permissions_complete_description'),
        };

        if (($freshness['is_stale'] ?? false) === true) {
            return $summary.' '.$this->overviewText('provider_permissions_stale_suffix');
        }

        return $summary;
    }

    private function reviewPackValue(?ReviewPack $reviewPack, ?EvidenceSnapshot $snapshot): string
    {
        if ($reviewPack instanceof ReviewPack) {
            return BadgeRenderer::spec(BadgeDomain::ReviewPackStatus, (string) $reviewPack->status)->label;
        }

        if ($snapshot instanceof EvidenceSnapshot) {
            return $this->overviewText('status_evidence_available');
        }

        return $this->overviewText('status_not_ready');
    }

    private function reviewPackTone(?ReviewPack $reviewPack, ?EvidenceSnapshot $snapshot): string
    {
        if ($reviewPack instanceof ReviewPack) {
            return BadgeRenderer::spec(BadgeDomain::ReviewPackStatus, (string) $reviewPack->status)->color;
        }

        if ($snapshot instanceof EvidenceSnapshot) {
            return 'info';
        }

        return 'warning';
    }

    private function reviewPackDescription(?ReviewPack $reviewPack, ?EvidenceSnapshot $snapshot): string
    {
        if ($reviewPack instanceof ReviewPack) {
            return $this->overviewText('review_pack_updated_prefix', ['time' => $reviewPack->generated_at?->diffForHumans()]);
        }

        if ($snapshot instanceof EvidenceSnapshot) {
            return $this->overviewText('review_pack_evidence_available_description');
        }

        return $this->overviewText('review_pack_unavailable_description');
    }

    private function customerSafeOutputStatus(?ReviewPack $reviewPack, ?EvidenceSnapshot $snapshot): string
    {
        if ($reviewPack instanceof ReviewPack) {
            return $this->reviewPackValue($reviewPack, $snapshot);
        }

        if ($snapshot instanceof EvidenceSnapshot) {
            return $this->overviewText('status_evidence_available');
        }

        return $this->overviewText('readiness_customer_safe_output_empty_status');
    }

    private function customerSafeOutputTone(?ReviewPack $reviewPack, ?EvidenceSnapshot $snapshot): string
    {
        if ($reviewPack instanceof ReviewPack) {
            return $this->reviewPackTone($reviewPack, $snapshot);
        }

        if ($snapshot instanceof EvidenceSnapshot) {
            return 'info';
        }

        return 'gray';
    }

    private function customerSafeOutputDescription(?ReviewPack $reviewPack, ?EvidenceSnapshot $snapshot): string
    {
        if ($reviewPack instanceof ReviewPack) {
            return $this->reviewPackDescription($reviewPack, $snapshot);
        }

        if ($snapshot instanceof EvidenceSnapshot) {
            return $this->overviewText('review_pack_evidence_available_description');
        }

        return $this->overviewText('readiness_customer_safe_output_empty_description');
    }

    /**
     * @param  array{active:int,expiring:int,expired:int,pending:int,total:int}  $exceptionStats
     */
    private function riskExceptionValue(array $exceptionStats): string
    {
        $needsAction = $exceptionStats['pending'] + $exceptionStats['expiring'] + $exceptionStats['expired'];

        if ($needsAction > 0) {
            return $this->overviewText('risk_exceptions_need_action_status', ['count' => $needsAction]);
        }

        if ($exceptionStats['active'] > 0) {
            return $this->overviewText('risk_exceptions_active_status', ['count' => $exceptionStats['active']]);
        }

        return $this->overviewText('status_calm');
    }

    /**
     * @param  array{active:int,expiring:int,expired:int,pending:int,total:int}  $exceptionStats
     */
    private function riskExceptionTone(array $exceptionStats): string
    {
        if ($exceptionStats['expired'] > 0) {
            return 'danger';
        }

        if ($exceptionStats['pending'] > 0 || $exceptionStats['expiring'] > 0) {
            return 'warning';
        }

        if ($exceptionStats['active'] > 0) {
            return 'info';
        }

        return 'success';
    }

    /**
     * @param  array{active:int,expiring:int,expired:int,pending:int,total:int}  $exceptionStats
     */
    private function riskExceptionDescription(array $exceptionStats): string
    {
        $needsAction = $exceptionStats['pending'] + $exceptionStats['expiring'] + $exceptionStats['expired'];

        if ($needsAction > 0) {
            return $this->overviewText('risk_exceptions_pending_description');
        }

        if ($exceptionStats['active'] > 0) {
            return $this->overviewText('risk_exceptions_active_description');
        }

        return $this->overviewText('risk_exceptions_calm_description');
    }

    private function providerHealthState(?ProviderConnection $connection): string
    {
        if (! $connection instanceof ProviderConnection) {
            return 'unknown';
        }

        $status = $connection->verification_status;

        if ($status instanceof \BackedEnum) {
            return (string) $status->value;
        }

        return trim((string) ($status ?? 'unknown')) ?: 'unknown';
    }

    private function relativeTime(?\DateTimeInterface $timestamp): ?string
    {
        return $timestamp?->diffForHumans();
    }

    private function relativeTimeFromString(mixed $timestamp): ?string
    {
        if (! is_string($timestamp) || trim($timestamp) === '') {
            return null;
        }

        try {
            return Carbon::parse($timestamp)->diffForHumans();
        } catch (\Throwable) {
            return null;
        }
    }

    /**
     * @param  array{label:string,value:string}|null  ...$items
     * @return list<array{label:string,value:string}>
     */
    private function cardMeta(?array ...$items): array
    {
        return array_values(array_filter($items, static fn (?array $item): bool => $item !== null));
    }

    /**
     * @return array{label:string,value:string}|null
     */
    private function metaItem(string $label, ?string $value): ?array
    {
        if (! is_string($value) || trim($value) === '') {
            return null;
        }

        return [
            'label' => $label,
            'value' => $value,
        ];
    }

    /**
     * @param  array<string, scalar|null>  $replace
     */
    private function overviewText(string $key, array $replace = []): string
    {
        return (string) __('localization.dashboard.overview.'.$key, $replace);
    }
}
