<?php

namespace App\Services\Inventory;

class InventoryMetaSanitizer
{
    /**
     * @param  array<string, mixed>  $meta
     * @return array{
     *     odata_type?: string,
     *     etag?: string|null,
     *     scope_tag_ids?: list<string>,
     *     assignment_target_count?: int|null,
     *     is_built_in?: bool,
     *     role_permission_count?: int,
     *     role_definition_id?: string,
     *     role_definition_name?: string,
     *     member_count?: int,
     *     scope_member_count?: int,
     *     resource_scope_count?: int,
     *     warnings?: list<string>
     * }
     */
    public function sanitize(array $meta): array
    {
        $sanitized = [];

        $odataType = $meta['odata_type'] ?? null;
        if (is_string($odataType) && trim($odataType) !== '') {
            $sanitized['odata_type'] = trim($odataType);
        }

        $etag = $meta['etag'] ?? null;
        if ($etag === null || is_string($etag)) {
            $sanitized['etag'] = $etag === null ? null : trim($etag);
        }

        $scopeTagIds = $meta['scope_tag_ids'] ?? null;
        if (is_array($scopeTagIds)) {
            $sanitized['scope_tag_ids'] = $this->stringList($scopeTagIds);
        }

        $assignmentTargetCount = $meta['assignment_target_count'] ?? null;
        if (is_int($assignmentTargetCount)) {
            $sanitized['assignment_target_count'] = $assignmentTargetCount;
        } elseif (is_numeric($assignmentTargetCount)) {
            $sanitized['assignment_target_count'] = (int) $assignmentTargetCount;
        } elseif ($assignmentTargetCount === null) {
            $sanitized['assignment_target_count'] = null;
        }

        $isBuiltIn = $meta['is_built_in'] ?? null;
        if (is_bool($isBuiltIn)) {
            $sanitized['is_built_in'] = $isBuiltIn;
        }

        foreach ([
            'role_permission_count',
            'member_count',
            'scope_member_count',
            'resource_scope_count',
        ] as $countKey) {
            $count = $meta[$countKey] ?? null;

            if (is_int($count)) {
                $sanitized[$countKey] = $count;
            } elseif (is_numeric($count)) {
                $sanitized[$countKey] = (int) $count;
            }
        }

        foreach ([
            'role_definition_id',
            'role_definition_name',
        ] as $stringKey) {
            $value = $meta[$stringKey] ?? null;

            if (! is_string($value)) {
                continue;
            }

            $value = trim($value);

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

            $sanitized[$stringKey] = $value;
        }

        $warnings = $meta['warnings'] ?? null;
        if (is_array($warnings)) {
            $sanitized['warnings'] = $this->boundedStringList($warnings, 25, 200);
        }

        return array_filter(
            $sanitized,
            static fn (mixed $value): bool => $value !== null && $value !== [] && $value !== ''
        );
    }

    /**
     * @param  list<mixed>  $values
     * @return list<string>
     */
    private function stringList(array $values): array
    {
        $result = [];

        foreach ($values as $value) {
            if (! is_string($value)) {
                continue;
            }

            $value = trim($value);
            if ($value === '') {
                continue;
            }

            $result[] = $value;
        }

        return array_values(array_unique($result));
    }

    /**
     * @param  list<mixed>  $values
     * @return list<string>
     */
    private function boundedStringList(array $values, int $maxItems, int $maxLen): array
    {
        $items = [];

        foreach ($values as $value) {
            if (count($items) >= $maxItems) {
                break;
            }

            if (! is_string($value)) {
                continue;
            }

            $value = trim($value);
            if ($value === '') {
                continue;
            }

            $items[] = mb_substr($value, 0, $maxLen);
        }

        return array_values(array_unique($items));
    }
}
