<?php

declare(strict_types=1);

namespace CpCreation\VitiCore\Commerce\Catalog;

final class CatalogSnapshotHasher
{
    public function hash(mixed $payload): string
    {
        $normalized = json_decode(
            json_encode($payload, \JSON_THROW_ON_ERROR | \JSON_UNESCAPED_SLASHES | \JSON_UNESCAPED_UNICODE),
            true,
            flags: \JSON_THROW_ON_ERROR,
        );
        $this->removeVolatileValues($normalized);

        return 'sha256:' . hash(
            'sha256',
            json_encode($normalized, \JSON_THROW_ON_ERROR | \JSON_UNESCAPED_SLASHES | \JSON_UNESCAPED_UNICODE),
        );
    }

    private function removeVolatileValues(mixed &$value): void
    {
        if (!\is_array($value)) {
            return;
        }

        unset($value['snapshot_at'], $value['generated_at'], $value['as_of'], $value['snapshot_hash']);
        foreach ($value as &$item) {
            $this->removeVolatileValues($item);
        }
        unset($item);

        // Les objets JSON sont des maps : leur ordre d'insertion ne fait pas
        // partie du contrat. L'ordre des listes (medias, variantes, options),
        // en revanche, reste volontairement significatif.
        if (!array_is_list($value)) {
            ksort($value);
        }
    }
}
