<?php

declare(strict_types=1);

namespace App\Services\Baselines;

use App\Models\ManagedEnvironment;
use App\Services\Baselines\Evidence\ContentEvidenceProvider;
use App\Services\Baselines\Evidence\MetaEvidenceProvider;
use App\Services\Baselines\Evidence\ResolvedEvidence;
use Carbon\CarbonImmutable;

final class CurrentStateHashResolver
{
    /**
     * @var list<CurrentStateEvidenceProvider>
     */
    private readonly array $providers;

    public function __construct(
        ContentEvidenceProvider $contentEvidenceProvider,
        MetaEvidenceProvider $metaEvidenceProvider,
    ) {
        $this->providers = [
            $contentEvidenceProvider,
            $metaEvidenceProvider,
        ];
    }

    /**
     * Resolve best-available current-state evidence per subject using the ordered provider chain.
     *
     * First-non-null wins.
     *
     * @param  list<array{policy_type: string, subject_external_id: string}>  $subjects
     * @return array<string, ResolvedEvidence|null> keyed by "policy_type|subject_external_id"
     */
    public function resolveForSubjects(
        ManagedEnvironment $tenant,
        array $subjects,
        ?CarbonImmutable $since = null,
        ?int $latestInventorySyncRunId = null,
    ): array {
        $results = [];
        $unresolved = [];

        foreach ($subjects as $subject) {
            $policyType = trim((string) ($subject['policy_type'] ?? ''));
            $externalId = trim((string) ($subject['subject_external_id'] ?? ''));

            if ($policyType === '' || $externalId === '') {
                continue;
            }

            $key = $policyType.'|'.$externalId;

            if (array_key_exists($key, $results)) {
                continue;
            }

            $results[$key] = null;
            $unresolved[$key] = [
                'policy_type' => $policyType,
                'subject_external_id' => $externalId,
            ];
        }

        foreach ($this->providers as $provider) {
            if ($unresolved === []) {
                break;
            }

            $resolved = $provider->resolve(
                tenant: $tenant,
                subjects: array_values($unresolved),
                since: $since,
                latestInventorySyncRunId: $latestInventorySyncRunId,
            );

            foreach ($resolved as $key => $evidence) {
                if (! array_key_exists($key, $unresolved)) {
                    continue;
                }

                $results[$key] = $evidence;
                unset($unresolved[$key]);
            }
        }

        return $results;
    }
}
