<?php

namespace App\Services\Inventory;

class InventorySelectionHasher
{
    /**
     * @param  array<string, mixed>  $selectionPayload
     * @return array{policy_types: list<string>, categories: list<string>, include_foundations: bool, include_dependencies: bool}
     */
    public function normalize(array $selectionPayload): array
    {
        $policyTypes = $this->stringList($selectionPayload['policy_types'] ?? []);
        sort($policyTypes);

        $categories = $this->stringList($selectionPayload['categories'] ?? []);
        sort($categories);

        return [
            'policy_types' => $policyTypes,
            'categories' => $categories,
            'include_foundations' => (bool) ($selectionPayload['include_foundations'] ?? false),
            'include_dependencies' => (bool) ($selectionPayload['include_dependencies'] ?? false),
        ];
    }

    /**
     * @param  array<string, mixed>  $selectionPayload
     */
    public function canonicalJson(array $selectionPayload): string
    {
        $normalized = $this->normalize($selectionPayload);
        $normalized = $this->ksortRecursive($normalized);

        return (string) json_encode($normalized, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
    }

    /**
     * @param  array<string, mixed>  $selectionPayload
     */
    public function hash(array $selectionPayload): string
    {
        return hash('sha256', $this->canonicalJson($selectionPayload));
    }

    /**
     * @return list<string>
     */
    private function stringList(mixed $value): array
    {
        if (! is_array($value)) {
            return [];
        }

        $result = [];
        foreach ($value as $item) {
            if (! is_string($item)) {
                continue;
            }

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

            $result[] = $item;
        }

        return array_values(array_unique($result));
    }

    private function ksortRecursive(mixed $value): mixed
    {
        if (! is_array($value)) {
            return $value;
        }

        $isList = array_is_list($value);
        if (! $isList) {
            ksort($value);
        }

        foreach ($value as $key => $child) {
            $value[$key] = $this->ksortRecursive($child);
        }

        return $value;
    }
}
