<?php

declare(strict_types=1);

/** Type-only JSON signature: no response values or personal data are persisted. */
function pocJsonContractSignature(string $json, bool $includeTypes = false): array
{
    $decoded = json_decode($json, false);
    if (json_last_error() !== JSON_ERROR_NONE) {
        throw new RuntimeException('Response is not valid JSON');
    }
    $types = [];
    $record = static function (string $path, string $type) use (&$types): void {
        $current = isset($types[$path]) ? explode('|', $types[$path]) : [];
        $current[] = $type;
        $current = array_values(array_unique($current));
        sort($current, SORT_STRING);
        $types[$path] = implode('|', $current);
    };
    $walk = static function ($value, string $path) use (&$walk, $record): void {
        if ($value instanceof stdClass) {
            $record($path, 'object');
            foreach (get_object_vars($value) as $key => $child) {
                $walk($child, $path . '.' . $key);
            }
            return;
        }
        if (is_array($value)) {
            $record($path, 'array');
            foreach ($value as $child) {
                $walk($child, $path . '[]');
            }
            if (!$value) $record($path . '[]', 'empty');
            return;
        }
        $record($path, $value === null ? 'null'
            : (is_bool($value) ? 'boolean'
                : (is_int($value) ? 'integer'
                    : (is_float($value) ? 'number' : 'string'))));
    };
    $walk($decoded, '$');
    foreach ($types as $path => $union) {
        $members = explode('|', $union);
        if (count($members) > 1 && in_array('empty', $members, true)) {
            $types[$path] = implode('|', array_values(array_diff($members, ['empty'])));
        }
    }
    ksort($types, SORT_STRING);
    $code = null;
    if ($decoded instanceof stdClass) {
        $code = $decoded->code ?? $decoded->status ?? null;
    }
    $result = [
        'sha256' => hash('sha256', json_encode($types, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)),
        'business_code_type' => gettype($code),
        'field_type_count' => count($types),
    ];
    if ($includeTypes) $result['types'] = $types;
    return $result;
}
