<?php

declare(strict_types=1);

namespace App\Support\Baselines;

use App\Models\BaselineProfile;
use App\Models\BaselineSnapshot;
use App\Models\BaselineSnapshotItem;
use App\Models\BaselineTenantAssignment;
use App\Models\Finding;
use App\Models\OperationRun;
use App\Models\ManagedEnvironment;
use App\Models\User;
use App\Services\Auth\CapabilityResolver;
use App\Services\Baselines\BaselineSnapshotTruthResolver;
use App\Support\Auth\Capabilities;
use App\Support\Badges\BadgeCatalog;
use App\Support\Badges\BadgeDomain;
use App\Support\Governance\PlatformSubjectDescriptorNormalizer;
use App\Support\Inventory\InventoryPolicyTypeMeta;
use App\Support\OperationRunOutcome;
use App\Support\OperationRunStatus;
use Illuminate\Support\Collection;
use Illuminate\Support\Str;

final class BaselineCompareMatrixBuilder
{
    public function __construct(
        private readonly BaselineSnapshotTruthResolver $snapshotTruthResolver,
        private readonly CapabilityResolver $capabilityResolver,
        private readonly BaselineCompareExplanationRegistry $explanationRegistry,
    ) {}

    /**
     * @param  array<string, mixed>  $filters
     * @return array<string, mixed>
     */
    public function build(BaselineProfile $profile, User $user, array $filters = []): array
    {
        $normalizedFilters = $this->normalizeFilters($filters);

        $assignments = BaselineTenantAssignment::query()
            ->inWorkspace((int) $profile->workspace_id)
            ->forBaselineProfile($profile)
            ->with('tenant')
            ->get();

        $this->capabilityResolver->primeMemberships(
            $user,
            $assignments
                ->pluck('managed_environment_id')
                ->filter(static fn (mixed $id): bool => is_numeric($id))
                ->map(static fn (mixed $id): int => (int) $id)
                ->all(),
        );

        $visibleTenants = $this->visibleTenants($assignments, $user);
        $referenceResolution = $this->snapshotTruthResolver->resolveCompareSnapshot($profile);
        $referenceSnapshot = $this->resolvedSnapshot($referenceResolution);
        $referenceReasonCode = is_string($referenceResolution['reason_code'] ?? null)
            ? trim((string) $referenceResolution['reason_code'])
            : null;

        $reference = [
            'workspaceId' => (int) $profile->workspace_id,
            'baselineProfileId' => (int) $profile->getKey(),
            'baselineProfileName' => (string) $profile->name,
            'baselineStatus' => $profile->status instanceof BaselineProfileStatus
                ? $profile->status->value
                : (string) $profile->status,
            'referenceSnapshotId' => $referenceSnapshot?->getKey(),
            'referenceSnapshotCapturedAt' => $referenceSnapshot?->captured_at?->toIso8601String(),
            'referenceState' => $referenceSnapshot instanceof BaselineSnapshot ? 'ready' : 'no_snapshot',
            'referenceReasonCode' => $referenceReasonCode,
            'assignedTenantCount' => $assignments->count(),
            'visibleTenantCount' => $visibleTenants->count(),
        ];

        $snapshotItems = $referenceSnapshot instanceof BaselineSnapshot
            ? BaselineSnapshotItem::query()
                ->where('baseline_snapshot_id', (int) $referenceSnapshot->getKey())
                ->orderBy('policy_type')
                ->orderBy('subject_key')
                ->orderBy('id')
                ->get()
            : collect();

        $policyTypeOptions = $snapshotItems
            ->pluck('policy_type')
            ->filter(static fn (mixed $type): bool => is_string($type) && trim($type) !== '')
            ->unique()
            ->sort()
            ->mapWithKeys(fn (string $type): array => [
                $type => $this->governedSubjectLabel($type),
            ])
            ->all();

        $bundle = [
            'reference' => $reference,
            'filters' => [
                'policyTypes' => $normalizedFilters['policyTypes'],
                'states' => $normalizedFilters['states'],
                'severities' => $normalizedFilters['severities'],
                'tenantSort' => $normalizedFilters['tenantSort'],
                'subjectSort' => $normalizedFilters['subjectSort'],
                'focusedSubjectKey' => $normalizedFilters['focusedSubjectKey'],
            ],
            'policyTypeOptions' => $policyTypeOptions,
            'stateOptions' => BadgeCatalog::options(BadgeDomain::BaselineCompareMatrixState, [
                'match',
                'differ',
                'missing',
                'ambiguous',
                'not_compared',
                'stale_result',
            ]),
            'severityOptions' => BadgeCatalog::options(BadgeDomain::FindingSeverity, [
                Finding::SEVERITY_LOW,
                Finding::SEVERITY_MEDIUM,
                Finding::SEVERITY_HIGH,
                Finding::SEVERITY_CRITICAL,
            ]),
            'tenantSortOptions' => [
                'tenant_name' => 'ManagedEnvironment name',
                'deviation_count' => 'Deviation count',
                'freshness_urgency' => 'Freshness urgency',
            ],
            'subjectSortOptions' => [
                'deviation_breadth' => 'Deviation breadth',
                'policy_type' => 'Governed subject',
                'display_name' => 'Display name',
            ],
            'stateLegend' => $this->legendSpecs(BadgeDomain::BaselineCompareMatrixState, [
                'match',
                'differ',
                'missing',
                'ambiguous',
                'not_compared',
                'stale_result',
            ]),
            'freshnessLegend' => $this->legendSpecs(BadgeDomain::BaselineCompareMatrixFreshness, [
                'fresh',
                'stale',
                'never_compared',
                'unknown',
            ]),
            'trustLegend' => $this->legendSpecs(BadgeDomain::BaselineCompareMatrixTrust, [
                'trustworthy',
                'limited_confidence',
                'diagnostic_only',
                'unusable',
            ]),
            'supportSurfaceState' => [
                'legendMode' => 'grouped',
                'showActiveFilterSummary' => true,
                'showLastUpdated' => true,
                'showAutoRefreshHint' => false,
                'showBlockingRefreshState' => false,
            ],
            'lastUpdatedAt' => now()->toIso8601String(),
            'tenantSummaries' => [],
            'subjectSummaries' => [],
            'rows' => [],
            'denseRows' => [],
            'compactResults' => [],
            'emptyState' => $this->emptyState(
                reference: $reference,
                snapshotItemsCount: $snapshotItems->count(),
                visibleTenantsCount: $visibleTenants->count(),
            ),
            'hasActiveRuns' => false,
        ];

        if (! $referenceSnapshot instanceof BaselineSnapshot) {
            return $bundle;
        }

        if ($visibleTenants->isEmpty()) {
            return $bundle;
        }

        if ($snapshotItems->isEmpty()) {
            return $bundle;
        }

        $tenantIds = $visibleTenants
            ->map(static fn (ManagedEnvironment $tenant): int => (int) $tenant->getKey())
            ->values()
            ->all();

        $latestRuns = OperationRun::latestBaselineCompareRunsForProfile(
            profile: $profile,
            tenantIds: $tenantIds,
            workspaceId: (int) $profile->workspace_id,
        )->keyBy(static fn (OperationRun $run): int => (int) $run->managed_environment_id);

        $completedRuns = OperationRun::latestBaselineCompareRunsForProfile(
            profile: $profile,
            tenantIds: $tenantIds,
            workspaceId: (int) $profile->workspace_id,
            completedOnly: true,
        )->keyBy(static fn (OperationRun $run): int => (int) $run->managed_environment_id);

        $findingMap = $this->findingMap($profile, $tenantIds, $completedRuns);
        $rows = [];

        foreach ($snapshotItems as $item) {
            if (! $item instanceof BaselineSnapshotItem) {
                continue;
            }

            $subjectKey = is_string($item->subject_key) ? trim($item->subject_key) : '';

            if ($subjectKey === '') {
                continue;
            }

            $subject = [
                'subjectKey' => $subjectKey,
                'policyType' => (string) $item->policy_type,
                'governedSubjectLabel' => $this->governedSubjectLabel((string) $item->policy_type),
                'subjectDescriptor' => $this->subjectDescriptor((string) $item->policy_type),
                'displayName' => $this->subjectDisplayName($item),
                'baselineExternalId' => is_string($item->subject_external_id) ? $item->subject_external_id : null,
            ];

            $cells = [];

            foreach ($visibleTenants as $tenant) {
                $tenantId = (int) $tenant->getKey();
                $latestRun = $latestRuns->get($tenantId);
                $completedRun = $completedRuns->get($tenantId);
                $cells[] = $this->cellFor(
                    item: $item,
                    tenant: $tenant,
                    referenceSnapshot: $referenceSnapshot,
                    latestRun: $latestRun instanceof OperationRun ? $latestRun : null,
                    completedRun: $completedRun instanceof OperationRun ? $completedRun : null,
                    finding: $findingMap[$this->cellKey($tenantId, $subjectKey)] ?? null,
                );
            }

            if (! $this->rowMatchesFilters($subject, $cells, $normalizedFilters)) {
                continue;
            }

            $rows[] = [
                'subject' => $this->subjectSummary($subject, $cells),
                'cells' => $cells,
            ];
        }

        $rows = $this->sortRows($rows, $normalizedFilters['subjectSort']);
        $tenantSummaries = $this->sortTenantSummaries(
            tenantSummaries: $this->tenantSummaries($visibleTenants, $latestRuns, $completedRuns, $rows, $referenceSnapshot),
            sort: $normalizedFilters['tenantSort'],
        );

        foreach ($rows as &$row) {
            $row['cells'] = $this->sortCellsForTenants($row['cells'], $tenantSummaries);
        }
        unset($row);

        $bundle['tenantSummaries'] = $tenantSummaries;
        $bundle['subjectSummaries'] = array_map(
            static fn (array $row): array => $row['subject'],
            $rows,
        );
        $bundle['rows'] = $rows;
        $bundle['denseRows'] = $rows;
        $bundle['compactResults'] = $this->compactResults($rows, $tenantSummaries);
        $bundle['emptyState'] = $this->emptyState(
            reference: $reference,
            snapshotItemsCount: $snapshotItems->count(),
            visibleTenantsCount: $visibleTenants->count(),
            renderedRowsCount: count($rows),
        );
        $bundle['hasActiveRuns'] = collect($tenantSummaries)
            ->contains(static fn (array $summary): bool => in_array((string) ($summary['compareRunStatus'] ?? ''), [
                OperationRunStatus::Queued->value,
                OperationRunStatus::Running->value,
            ], true));
        $bundle['supportSurfaceState']['showAutoRefreshHint'] = $bundle['hasActiveRuns'];

        return $bundle;
    }

    /**
     * @param  array<string, mixed>  $filters
     * @return array{
     *     policyTypes: list<string>,
     *     states: list<string>,
     *     severities: list<string>,
     *     tenantSort: string,
     *     subjectSort: string,
     *     focusedSubjectKey: ?string
     * }
     */
    private function normalizeFilters(array $filters): array
    {
        $policyTypes = $this->normalizeStringList($filters['policy_type'] ?? $filters['policyTypes'] ?? []);
        $states = array_values(array_intersect(
            $this->normalizeStringList($filters['state'] ?? $filters['states'] ?? []),
            ['match', 'differ', 'missing', 'ambiguous', 'not_compared', 'stale_result'],
        ));
        $severities = array_values(array_intersect(
            $this->normalizeStringList($filters['severity'] ?? $filters['severities'] ?? []),
            [Finding::SEVERITY_LOW, Finding::SEVERITY_MEDIUM, Finding::SEVERITY_HIGH, Finding::SEVERITY_CRITICAL],
        ));
        $tenantSort = in_array((string) ($filters['tenant_sort'] ?? $filters['tenantSort'] ?? 'tenant_name'), [
            'tenant_name',
            'deviation_count',
            'freshness_urgency',
        ], true)
            ? (string) ($filters['tenant_sort'] ?? $filters['tenantSort'] ?? 'tenant_name')
            : 'tenant_name';
        $subjectSort = in_array((string) ($filters['subject_sort'] ?? $filters['subjectSort'] ?? 'deviation_breadth'), [
            'deviation_breadth',
            'policy_type',
            'display_name',
        ], true)
            ? (string) ($filters['subject_sort'] ?? $filters['subjectSort'] ?? 'deviation_breadth')
            : 'deviation_breadth';
        $focusedSubjectKey = $filters['subject_key'] ?? $filters['focusedSubjectKey'] ?? null;
        $focusedSubjectKey = is_string($focusedSubjectKey) && trim($focusedSubjectKey) !== ''
            ? trim($focusedSubjectKey)
            : null;

        return [
            'policyTypes' => $policyTypes,
            'states' => $states,
            'severities' => $severities,
            'tenantSort' => $tenantSort,
            'subjectSort' => $subjectSort,
            'focusedSubjectKey' => $focusedSubjectKey,
        ];
    }

    /**
     * @return list<string>
     */
    private function normalizeStringList(mixed $value): array
    {
        $values = is_array($value) ? $value : [$value];

        return array_values(array_unique(array_filter(array_map(static function (mixed $item): ?string {
            if (! is_string($item)) {
                return null;
            }

            $normalized = trim($item);

            return $normalized !== '' ? $normalized : null;
        }, $values))));
    }

    /**
     * @param  Collection<int, BaselineTenantAssignment>  $assignments
     * @return Collection<int, ManagedEnvironment>
     */
    private function visibleTenants(Collection $assignments, User $user): Collection
    {
        return $assignments
            ->map(static fn (BaselineTenantAssignment $assignment): ?ManagedEnvironment => $assignment->tenant)
            ->filter(fn (?ManagedEnvironment $tenant): bool => $tenant instanceof ManagedEnvironment
                && $this->capabilityResolver->isMember($user, $tenant)
                && $this->capabilityResolver->can($user, $tenant, Capabilities::TENANT_VIEW))
            ->sortBy(static fn (ManagedEnvironment $tenant): string => Str::lower((string) $tenant->name))
            ->values();
    }

    /**
     * @param  array<string, mixed>  $resolution
     */
    private function resolvedSnapshot(array $resolution): ?BaselineSnapshot
    {
        $snapshot = $resolution['effective_snapshot'] ?? $resolution['snapshot'] ?? null;

        return $snapshot instanceof BaselineSnapshot ? $snapshot : null;
    }

    /**
     * @param  array<int, int>  $tenantIds
     * @param  Collection<int, OperationRun>  $completedRuns
     * @return array<string, Finding>
     */
    private function findingMap(BaselineProfile $profile, array $tenantIds, Collection $completedRuns): array
    {
        $findings = Finding::query()
            ->baselineCompareForProfile($profile)
            ->whereIn('managed_environment_id', $tenantIds)
            ->orderByDesc('last_seen_at')
            ->orderByDesc('id')
            ->get();

        $map = [];

        foreach ($findings as $finding) {
            if (! $finding instanceof Finding) {
                continue;
            }

            $tenantId = (int) $finding->managed_environment_id;
            $subjectKey = $this->subjectKeyForFinding($finding);

            if ($subjectKey === null) {
                continue;
            }

            $completedRun = $completedRuns->get($tenantId);

            if (
                $completedRun instanceof OperationRun
                && (int) ($finding->current_operation_run_id ?? 0) !== (int) $completedRun->getKey()
            ) {
                continue;
            }

            $cellKey = $this->cellKey($tenantId, $subjectKey);

            if (! array_key_exists($cellKey, $map)) {
                $map[$cellKey] = $finding;
            }
        }

        return $map;
    }

    private function subjectKeyForFinding(Finding $finding): ?string
    {
        $subjectKey = data_get($finding->evidence_jsonb, 'subject_key');

        if (is_string($subjectKey) && trim($subjectKey) !== '') {
            return trim($subjectKey);
        }

        return null;
    }

    private function cellKey(int $tenantId, string $subjectKey): string
    {
        return $tenantId.'|'.trim(mb_strtolower($subjectKey));
    }

    private function subjectDisplayName(BaselineSnapshotItem $item): ?string
    {
        $displayName = data_get($item->meta_jsonb, 'display_name');

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

        return is_string($item->subject_key) && trim($item->subject_key) !== ''
            ? Str::headline($item->subject_key)
            : null;
    }

    private function cellFor(
        BaselineSnapshotItem $item,
        ManagedEnvironment $tenant,
        BaselineSnapshot $referenceSnapshot,
        ?OperationRun $latestRun,
        ?OperationRun $completedRun,
        ?Finding $finding,
    ): array {
        $subjectKey = (string) $item->subject_key;
        $policyType = (string) $item->policy_type;
        $completedAt = $completedRun?->finished_at;
        $policyTypeCovered = $this->policyTypeCovered($completedRun, $policyType);
        $subjectReasons = $completedRun instanceof OperationRun
            ? (BaselineCompareEvidenceGapDetails::subjectReasonsFromOperationRun($completedRun)[BaselineCompareEvidenceGapDetails::subjectCompositeKey($policyType, $subjectKey)] ?? [])
            : [];
        $reasonCode = $subjectReasons[0] ?? $this->runReasonCode($completedRun);
        $changeType = is_string(data_get($finding?->evidence_jsonb, 'change_type')) ? (string) data_get($finding?->evidence_jsonb, 'change_type') : null;
        $staleResult = $this->isStaleResult($completedRun, $referenceSnapshot);
        $tenantTrustLevel = $this->tenantTrustLevel($completedRun);

        $state = match (true) {
            ! $completedRun instanceof OperationRun => 'not_compared',
            (string) $completedRun->outcome === OperationRunOutcome::Failed->value => 'not_compared',
            ! $policyTypeCovered => 'not_compared',
            $staleResult => 'stale_result',
            $subjectReasons !== [] => 'ambiguous',
            $changeType === 'missing_policy' => 'missing',
            $finding instanceof Finding => 'differ',
            default => 'match',
        };

        $trustLevel = match ($state) {
            'not_compared' => 'unusable',
            'stale_result' => 'limited_confidence',
            'ambiguous' => 'diagnostic_only',
            default => $tenantTrustLevel,
        };

        return [
            'tenantId' => (int) $tenant->getKey(),
            'subjectKey' => $subjectKey,
            'state' => $state,
            'severity' => $finding instanceof Finding ? (string) $finding->severity : null,
            'trustLevel' => $trustLevel,
            'freshnessState' => $this->freshnessState($completedRun, $referenceSnapshot),
            'attentionLevel' => $this->attentionLevel($state, $finding instanceof Finding ? (string) $finding->severity : null),
            'reasonSummary' => $this->reasonSummary($state, $reasonCode, $policyTypeCovered),
            'reasonCode' => $reasonCode,
            'compareRunId' => $completedRun?->getKey(),
            'findingId' => $finding?->getKey(),
            'findingWorkflowState' => $finding instanceof Finding ? (string) $finding->status : null,
            'lastComparedAt' => $completedAt?->toIso8601String(),
            'policyTypeCovered' => $policyTypeCovered,
            'latestRunId' => $latestRun?->getKey(),
            'latestRunStatus' => $latestRun?->status,
        ];
    }

    private function policyTypeCovered(?OperationRun $run, string $policyType): bool
    {
        if (! $run instanceof OperationRun) {
            return false;
        }

        $coverage = data_get($run->context, 'baseline_compare.coverage');

        if (! is_array($coverage)) {
            return true;
        }

        $coveredTypes = is_array($coverage['covered_types'] ?? null)
            ? array_values(array_filter($coverage['covered_types'], 'is_string'))
            : [];
        $uncoveredTypes = is_array($coverage['uncovered_types'] ?? null)
            ? array_values(array_filter($coverage['uncovered_types'], 'is_string'))
            : [];

        if (in_array($policyType, $uncoveredTypes, true)) {
            return false;
        }

        if ($coveredTypes === []) {
            return true;
        }

        return in_array($policyType, $coveredTypes, true);
    }

    private function runReasonCode(?OperationRun $run): ?string
    {
        $reasonCode = data_get($run?->context, 'baseline_compare.reason_code');

        return is_string($reasonCode) && trim($reasonCode) !== ''
            ? trim($reasonCode)
            : null;
    }

    private function attentionLevel(string $state, ?string $severity): string
    {
        if (in_array($state, ['differ', 'missing', 'ambiguous'], true) || in_array($severity, [
            Finding::SEVERITY_HIGH,
            Finding::SEVERITY_CRITICAL,
        ], true)) {
            return 'needs_attention';
        }

        if (in_array($state, ['stale_result', 'not_compared'], true)) {
            return 'refresh_recommended';
        }

        if ($state === 'match') {
            return 'aligned';
        }

        return 'review';
    }

    private function reasonSummary(string $state, ?string $reasonCode, bool $policyTypeCovered): ?string
    {
        return match ($state) {
            'differ' => 'A baseline compare finding exists for this subject.',
            'missing' => 'The reference subject is missing from the tenant result.',
            'ambiguous' => $reasonCode !== null
                ? Str::headline(str_replace(['.', '_'], ' ', $reasonCode))
                : 'Identity or evidence stayed ambiguous.',
            'stale_result' => 'Refresh recommended before acting on this result.',
            'not_compared' => $policyTypeCovered
                ? 'No completed compare result is available yet.'
                : 'Governed subject coverage was not proven in the latest compare run.',
            default => null,
        };
    }

    private function isStaleResult(?OperationRun $run, BaselineSnapshot $referenceSnapshot): bool
    {
        if (! $run instanceof OperationRun || ! $run->finished_at) {
            return false;
        }

        $runSnapshotId = data_get($run->context, 'baseline_snapshot_id');

        if (is_numeric($runSnapshotId) && (int) $runSnapshotId !== (int) $referenceSnapshot->getKey()) {
            return true;
        }

        if ($referenceSnapshot->captured_at && $run->finished_at->lt($referenceSnapshot->captured_at)) {
            return true;
        }

        return BaselineCompareSummaryAssessor::isStaleComparedAt($run->finished_at);
    }

    private function tenantTrustLevel(?OperationRun $run): string
    {
        return BadgeCatalog::normalizeState(
            $this->explanationRegistry->trustLevelForRun($run),
        ) ?? 'unusable';
    }

    /**
     * @param  array<string, mixed>  $subject
     * @param  list<array<string, mixed>>  $cells
     * @param  array<string, mixed>  $filters
     */
    private function rowMatchesFilters(array $subject, array $cells, array $filters): bool
    {
        if ($filters['policyTypes'] !== [] && ! in_array((string) $subject['policyType'], $filters['policyTypes'], true)) {
            return false;
        }

        if ($filters['focusedSubjectKey'] !== null && (string) $subject['subjectKey'] !== $filters['focusedSubjectKey']) {
            return false;
        }

        foreach ($cells as $cell) {
            if ($filters['states'] !== [] && ! in_array((string) ($cell['state'] ?? ''), $filters['states'], true)) {
                continue;
            }

            if ($filters['severities'] !== [] && ! in_array((string) ($cell['severity'] ?? ''), $filters['severities'], true)) {
                continue;
            }

            return true;
        }

        return $filters['states'] === [] && $filters['severities'] === [];
    }

    /**
     * @param  list<array<string, mixed>>  $cells
     * @return array<string, mixed>
     */
    private function subjectSummary(array $subject, array $cells): array
    {
        return [
            'subjectKey' => $subject['subjectKey'],
            'policyType' => $subject['policyType'],
            'governedSubjectLabel' => $subject['governedSubjectLabel'] ?? $this->governedSubjectLabel((string) $subject['policyType']),
            'subjectDescriptor' => $subject['subjectDescriptor'] ?? $this->subjectDescriptor((string) $subject['policyType']),
            'displayName' => $subject['displayName'],
            'baselineExternalId' => $subject['baselineExternalId'],
            'deviationBreadth' => $this->countStates($cells, ['differ', 'missing']),
            'missingBreadth' => $this->countStates($cells, ['missing']),
            'ambiguousBreadth' => $this->countStates($cells, ['ambiguous']),
            'notComparedBreadth' => $this->countStates($cells, ['not_compared']),
            'maxSeverity' => $this->maxSeverity($cells),
            'trustLevel' => $this->worstTrustLevel($cells),
            'attentionLevel' => $this->worstAttentionLevel($cells),
        ];
    }

    /**
     * @param  Collection<int, ManagedEnvironment>  $visibleTenants
     * @param  Collection<int, OperationRun>  $latestRuns
     * @param  Collection<int, OperationRun>  $completedRuns
     * @param  list<array<string, mixed>>  $rows
     * @return list<array<string, mixed>>
     */
    private function tenantSummaries(
        Collection $visibleTenants,
        Collection $latestRuns,
        Collection $completedRuns,
        array $rows,
        BaselineSnapshot $referenceSnapshot,
    ): array {
        $summaries = [];

        foreach ($visibleTenants as $tenant) {
            $tenantId = (int) $tenant->getKey();
            $latestRun = $latestRuns->get($tenantId);
            $completedRun = $completedRuns->get($tenantId);
            $cells = array_map(
                static fn (array $row): array => collect($row['cells'])->firstWhere('tenantId', $tenantId) ?? [],
                $rows,
            );

            $summaries[] = [
                'tenantId' => $tenantId,
                'tenantName' => (string) $tenant->name,
                'compareRunId' => $latestRun?->getKey(),
                'compareRunStatus' => $latestRun?->status,
                'compareRunOutcome' => $latestRun?->outcome,
                'freshnessState' => $this->freshnessState($completedRun, $referenceSnapshot),
                'lastComparedAt' => $completedRun?->finished_at?->toIso8601String(),
                'matchedCount' => $this->countStates($cells, ['match']),
                'differingCount' => $this->countStates($cells, ['differ']),
                'missingCount' => $this->countStates($cells, ['missing']),
                'ambiguousCount' => $this->countStates($cells, ['ambiguous']),
                'notComparedCount' => $this->countStates($cells, ['not_compared']),
                'maxSeverity' => $this->maxSeverity($cells),
                'trustLevel' => $this->worstTrustLevel($cells),
            ];
        }

        return $summaries;
    }

    private function freshnessState(?OperationRun $completedRun, BaselineSnapshot $referenceSnapshot): string
    {
        if (! $completedRun instanceof OperationRun) {
            return 'never_compared';
        }

        if ((string) $completedRun->outcome === OperationRunOutcome::Failed->value) {
            return 'unknown';
        }

        if ($this->isStaleResult($completedRun, $referenceSnapshot)) {
            return 'stale';
        }

        return 'fresh';
    }

    /**
     * @param  list<array<string, mixed>>  $cells
     * @param  array<int, string>  $states
     */
    private function countStates(array $cells, array $states): int
    {
        return count(array_filter(
            $cells,
            static fn (array $cell): bool => in_array((string) ($cell['state'] ?? ''), $states, true),
        ));
    }

    /**
     * @param  list<array<string, mixed>>  $cells
     */
    private function maxSeverity(array $cells): ?string
    {
        $ranked = collect($cells)
            ->map(static fn (array $cell): ?string => is_string($cell['severity'] ?? null) ? (string) $cell['severity'] : null)
            ->filter()
            ->sortByDesc(fn (string $severity): int => $this->severityRank($severity))
            ->values();

        return $ranked->first();
    }

    private function severityRank(string $severity): int
    {
        return match ($severity) {
            Finding::SEVERITY_CRITICAL => 4,
            Finding::SEVERITY_HIGH => 3,
            Finding::SEVERITY_MEDIUM => 2,
            Finding::SEVERITY_LOW => 1,
            default => 0,
        };
    }

    /**
     * @param  list<array<string, mixed>>  $cells
     */
    private function worstTrustLevel(array $cells): string
    {
        return collect($cells)
            ->map(static fn (array $cell): string => (string) ($cell['trustLevel'] ?? 'unusable'))
            ->sortByDesc(fn (string $trust): int => $this->trustRank($trust))
            ->first() ?? 'unusable';
    }

    private function trustRank(string $trustLevel): int
    {
        return match ($trustLevel) {
            'unusable' => 4,
            'diagnostic_only' => 3,
            'limited_confidence' => 2,
            'trustworthy' => 1,
            default => 0,
        };
    }

    /**
     * @param  list<array<string, mixed>>  $cells
     */
    private function worstAttentionLevel(array $cells): string
    {
        return collect($cells)
            ->map(static fn (array $cell): string => (string) ($cell['attentionLevel'] ?? 'review'))
            ->sortByDesc(fn (string $level): int => $this->attentionRank($level))
            ->first() ?? 'review';
    }

    private function attentionRank(string $attentionLevel): int
    {
        return match ($attentionLevel) {
            'needs_attention' => 4,
            'refresh_recommended' => 3,
            'review' => 2,
            'aligned' => 1,
            default => 0,
        };
    }

    /**
     * @param  list<array<string, mixed>>  $rows
     * @return list<array<string, mixed>>
     */
    private function sortRows(array $rows, string $sort): array
    {
        usort($rows, function (array $left, array $right) use ($sort): int {
            $leftSubject = $left['subject'] ?? [];
            $rightSubject = $right['subject'] ?? [];

            return match ($sort) {
                'policy_type' => [
                    Str::lower((string) ($leftSubject['governedSubjectLabel'] ?? $leftSubject['policyType'] ?? '')),
                    Str::lower((string) ($leftSubject['displayName'] ?? '')),
                ] <=> [
                    Str::lower((string) ($rightSubject['governedSubjectLabel'] ?? $rightSubject['policyType'] ?? '')),
                    Str::lower((string) ($rightSubject['displayName'] ?? '')),
                ],
                'display_name' => [Str::lower((string) ($leftSubject['displayName'] ?? '')), (string) ($leftSubject['subjectKey'] ?? '')]
                    <=> [Str::lower((string) ($rightSubject['displayName'] ?? '')), (string) ($rightSubject['subjectKey'] ?? '')],
                default => [
                    -1 * (int) ($leftSubject['deviationBreadth'] ?? 0),
                    -1 * (int) ($leftSubject['ambiguousBreadth'] ?? 0),
                    Str::lower((string) ($leftSubject['displayName'] ?? '')),
                ] <=> [
                    -1 * (int) ($rightSubject['deviationBreadth'] ?? 0),
                    -1 * (int) ($rightSubject['ambiguousBreadth'] ?? 0),
                    Str::lower((string) ($rightSubject['displayName'] ?? '')),
                ],
            };
        });

        return array_values($rows);
    }

    /**
     * @param  list<array<string, mixed>>  $tenantSummaries
     * @return list<array<string, mixed>>
     */
    private function sortTenantSummaries(array $tenantSummaries, string $sort): array
    {
        usort($tenantSummaries, function (array $left, array $right) use ($sort): int {
            return match ($sort) {
                'deviation_count' => [
                    -1 * ((int) ($left['differingCount'] ?? 0) + (int) ($left['missingCount'] ?? 0) + (int) ($left['ambiguousCount'] ?? 0)),
                    Str::lower((string) ($left['tenantName'] ?? '')),
                ] <=> [
                    -1 * ((int) ($right['differingCount'] ?? 0) + (int) ($right['missingCount'] ?? 0) + (int) ($right['ambiguousCount'] ?? 0)),
                    Str::lower((string) ($right['tenantName'] ?? '')),
                ],
                'freshness_urgency' => [
                    -1 * $this->freshnessRank((string) ($left['freshnessState'] ?? 'unknown')),
                    Str::lower((string) ($left['tenantName'] ?? '')),
                ] <=> [
                    -1 * $this->freshnessRank((string) ($right['freshnessState'] ?? 'unknown')),
                    Str::lower((string) ($right['tenantName'] ?? '')),
                ],
                default => Str::lower((string) ($left['tenantName'] ?? '')) <=> Str::lower((string) ($right['tenantName'] ?? '')),
            };
        });

        return array_values($tenantSummaries);
    }

    private function freshnessRank(string $freshnessState): int
    {
        return match ($freshnessState) {
            'stale' => 4,
            'unknown' => 3,
            'never_compared' => 2,
            'fresh' => 1,
            default => 0,
        };
    }

    /**
     * @param  list<array<string, mixed>>  $cells
     * @param  list<array<string, mixed>>  $tenantSummaries
     * @return list<array<string, mixed>>
     */
    private function sortCellsForTenants(array $cells, array $tenantSummaries): array
    {
        $order = collect($tenantSummaries)
            ->values()
            ->mapWithKeys(static fn (array $summary, int $index): array => [
                (int) ($summary['tenantId'] ?? 0) => $index,
            ]);

        usort($cells, static fn (array $left, array $right): int => ($order[(int) ($left['tenantId'] ?? 0)] ?? 9999) <=> ($order[(int) ($right['tenantId'] ?? 0)] ?? 9999));

        return array_values($cells);
    }

    /**
     * @param  list<array<string, mixed>>  $rows
     * @param  list<array<string, mixed>>  $tenantSummaries
     * @return list<array<string, mixed>>
     */
    private function compactResults(array $rows, array $tenantSummaries): array
    {
        if (count($tenantSummaries) !== 1) {
            return [];
        }

        $tenantSummary = $tenantSummaries[0];
        $tenantId = (int) ($tenantSummary['tenantId'] ?? 0);

        if ($tenantId <= 0) {
            return [];
        }

        return array_values(array_map(function (array $row) use ($tenantId, $tenantSummary): array {
            $subject = is_array($row['subject'] ?? null) ? $row['subject'] : [];
            $cell = collect($row['cells'] ?? [])->firstWhere('tenantId', $tenantId) ?? [];

            return [
                'tenantId' => $tenantId,
                'tenantName' => (string) ($tenantSummary['tenantName'] ?? 'ManagedEnvironment'),
                'subjectKey' => (string) ($subject['subjectKey'] ?? ''),
                'displayName' => $subject['displayName'] ?? $subject['subjectKey'] ?? 'Subject',
                'policyType' => (string) ($subject['policyType'] ?? ''),
                'governedSubjectLabel' => (string) ($subject['governedSubjectLabel'] ?? $this->governedSubjectLabel((string) ($subject['policyType'] ?? ''))),
                'subjectDescriptor' => $subject['subjectDescriptor'] ?? $this->subjectDescriptor((string) ($subject['policyType'] ?? '')),
                'baselineExternalId' => $subject['baselineExternalId'] ?? null,
                'deviationBreadth' => (int) ($subject['deviationBreadth'] ?? 0),
                'missingBreadth' => (int) ($subject['missingBreadth'] ?? 0),
                'ambiguousBreadth' => (int) ($subject['ambiguousBreadth'] ?? 0),
                'state' => (string) ($cell['state'] ?? 'not_compared'),
                'freshnessState' => (string) ($cell['freshnessState'] ?? 'unknown'),
                'trustLevel' => (string) ($cell['trustLevel'] ?? 'unusable'),
                'attentionLevel' => (string) ($cell['attentionLevel'] ?? 'review'),
                'severity' => $cell['severity'] ?? null,
                'reasonSummary' => $cell['reasonSummary'] ?? null,
                'reasonCode' => $cell['reasonCode'] ?? null,
                'compareRunId' => $cell['compareRunId'] ?? null,
                'findingId' => $cell['findingId'] ?? null,
                'lastComparedAt' => $cell['lastComparedAt'] ?? null,
                'policyTypeCovered' => $cell['policyTypeCovered'] ?? true,
            ];
        }, $rows));
    }

    /**
     * @param  array<string, mixed>  $reference
     * @return array{title: string, body: string}|null
     */
    private function emptyState(
        array $reference,
        int $snapshotItemsCount,
        int $visibleTenantsCount,
        int $renderedRowsCount = 0,
    ): ?array {
        if (($reference['referenceState'] ?? null) !== 'ready') {
            return [
                'title' => 'No usable reference snapshot',
                'body' => 'Capture a complete baseline snapshot before using the compare matrix.',
            ];
        }

        if ((int) ($reference['assignedTenantCount'] ?? 0) === 0) {
            return [
                'title' => 'No assigned environments',
                'body' => 'Assign environments to this baseline profile to build the visible compare set.',
            ];
        }

        if ($visibleTenantsCount === 0) {
            return [
                'title' => 'No visible assigned environments',
                'body' => 'This baseline has assigned environments, but none are visible in your current environment scope.',
            ];
        }

        if ($snapshotItemsCount === 0) {
            return [
                'title' => 'No baseline subjects',
                'body' => 'The active reference snapshot completed without any baseline subjects to compare.',
            ];
        }

        if ($renderedRowsCount === 0) {
            return [
                'title' => 'No rows match the current filters',
                'body' => 'Adjust the governed subject, state, or severity filters to broaden the matrix view.',
            ];
        }

        return null;
    }

    /**
     * @param  array<int, string>  $values
     * @return list<array<string, mixed>>
     */
    private function legendSpecs(BadgeDomain $domain, array $values): array
    {
        return array_map(
            static function (string $value) use ($domain): array {
                $spec = BadgeCatalog::spec($domain, $value);

                return [
                    'value' => $value,
                    'label' => $spec->label,
                    'color' => $spec->color,
                    'icon' => $spec->icon,
                    'iconColor' => $spec->iconColor,
                ];
            },
            $values,
        );
    }

    private function governedSubjectLabel(string $policyType): string
    {
        return (string) data_get(
            $this->subjectDescriptor($policyType),
            'display_label',
            InventoryPolicyTypeMeta::label($policyType) ?? Str::headline($policyType),
        );
    }

    /**
     * @return array<string, mixed>
     */
    private function subjectDescriptor(string $policyType): array
    {
        static $cache = [];

        if (array_key_exists($policyType, $cache)) {
            return $cache[$policyType];
        }

        $result = app(PlatformSubjectDescriptorNormalizer::class)->fromArray([
            'policy_type' => $policyType,
        ], 'baseline_compare_matrix');

        return $cache[$policyType] = $result->descriptor->toArray();
    }
}
