<?php

declare(strict_types=1);

namespace App\Services\Baselines;

final class InventoryMetaContract
{
    public const int VERSION = 1;

    /**
     * Build the v1 meta contract for hashing and auditability.
     *
     * Missing signals MUST be represented as null (not omitted) to keep the hash stable across partial inventories.
     *
     * @param  array<string, mixed>  $metaJsonb
     * @return array{
     *   version: int,
     *   policy_type: string,
     *   subject_external_id: string,
     *   odata_type: ?string,
     *   etag: ?string,
     *   scope_tag_ids: ?list<string>,
     *   assignment_target_count: ?int
     * }
     */
    public function build(string $policyType, string $subjectExternalId, array $metaJsonb): array
    {
        $odataType = $metaJsonb['odata_type'] ?? null;
        $odataType = is_string($odataType) ? trim($odataType) : null;
        $odataType = $odataType !== '' ? $odataType : null;

        $etag = $metaJsonb['etag'] ?? null;
        $etag = is_string($etag) ? trim($etag) : null;
        $etag = $etag !== '' ? $etag : null;

        $scopeTagIds = $metaJsonb['scope_tag_ids'] ?? null;
        $scopeTagIds = is_array($scopeTagIds) ? $this->normalizeStringList($scopeTagIds) : null;

        $assignmentTargetCount = $metaJsonb['assignment_target_count'] ?? null;
        $assignmentTargetCount = is_numeric($assignmentTargetCount) ? (int) $assignmentTargetCount : null;

        return [
            'version' => self::VERSION,
            'policy_type' => trim($policyType),
            'subject_external_id' => trim($subjectExternalId),
            'odata_type' => $odataType,
            'etag' => $etag,
            'scope_tag_ids' => $scopeTagIds,
            'assignment_target_count' => $assignmentTargetCount,
        ];
    }

    /**
     * @param  array<int, mixed>  $values
     * @return list<string>
     */
    private function normalizeStringList(array $values): array
    {
        $values = array_values(array_filter($values, 'is_string'));
        $values = array_map('trim', $values);
        $values = array_values(array_filter($values, fn (string $value): bool => $value !== ''));
        $values = array_values(array_unique($values));

        sort($values, SORT_STRING);

        return $values;
    }
}
