<?php

declare(strict_types=1);

namespace App\Services\Baselines\Evidence;

use App\Models\InventoryItem;
use App\Models\ManagedEnvironment;
use App\Services\Baselines\BaselineSnapshotIdentity;
use App\Services\Baselines\CurrentStateEvidenceProvider;
use Carbon\CarbonImmutable;
use Illuminate\Support\Collection;

final class MetaEvidenceProvider implements CurrentStateEvidenceProvider
{
    public function __construct(
        private readonly BaselineSnapshotIdentity $snapshotIdentity,
    ) {}

    public function name(): string
    {
        return 'inventory';
    }

    public function resolve(ManagedEnvironment $tenant, array $subjects, ?CarbonImmutable $since = null, ?int $latestInventorySyncRunId = null): array
    {
        if ($subjects === []) {
            return [];
        }

        $requestedKeys = $this->requestedKeys($subjects);

        if ($requestedKeys === []) {
            return [];
        }

        $policyTypes = array_values(array_unique(array_map(
            static fn (array $subject): string => trim((string) ($subject['policy_type'] ?? '')),
            $subjects,
        )));
        $policyTypes = array_values(array_filter($policyTypes, static fn (string $value): bool => $value !== ''));

        $externalIds = array_values(array_unique(array_map(
            static fn (array $subject): string => trim((string) ($subject['subject_external_id'] ?? '')),
            $subjects,
        )));
        $externalIds = array_values(array_filter($externalIds, static fn (string $value): bool => $value !== ''));

        if ($policyTypes === [] || $externalIds === []) {
            return [];
        }

        $query = InventoryItem::query()
            ->where('managed_environment_id', (int) $tenant->getKey())
            ->whereIn('policy_type', $policyTypes)
            ->whereIn('external_id', $externalIds);

        if (is_int($latestInventorySyncRunId) && $latestInventorySyncRunId > 0) {
            $query->where('last_seen_operation_run_id', $latestInventorySyncRunId);
        }

        /** @var Collection<int, InventoryItem> $inventoryItems */
        $inventoryItems = $query->get();

        $resolved = [];

        foreach ($inventoryItems as $item) {
            if (! $item instanceof InventoryItem) {
                continue;
            }

            $key = (string) $item->policy_type.'|'.(string) $item->external_id;

            if (! array_key_exists($key, $requestedKeys)) {
                continue;
            }

            $metaJsonb = is_array($item->meta_jsonb) ? $item->meta_jsonb : [];

            $hash = $this->snapshotIdentity->hashItemContent(
                policyType: (string) $item->policy_type,
                subjectExternalId: (string) $item->external_id,
                metaJsonb: $metaJsonb,
            );

            $observedAt = $item->last_seen_at ? CarbonImmutable::instance($item->last_seen_at) : null;
            $observedOperationRunId = is_numeric($item->last_seen_operation_run_id)
                ? (int) $item->last_seen_operation_run_id
                : null;

            $resolved[$key] = new ResolvedEvidence(
                policyType: (string) $item->policy_type,
                subjectExternalId: (string) $item->external_id,
                hash: $hash,
                fidelity: EvidenceProvenance::FidelityMeta,
                source: EvidenceProvenance::SourceInventory,
                observedAt: $observedAt,
                observedOperationRunId: $observedOperationRunId,
                meta: [],
            );
        }

        return $resolved;
    }

    /**
     * @param  list<array{policy_type: string, subject_external_id: string}>  $subjects
     * @return array<string, true>
     */
    private function requestedKeys(array $subjects): array
    {
        $keys = [];

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

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

            $keys[$policyType.'|'.$externalId] = true;
        }

        return $keys;
    }
}
