<?php

declare(strict_types=1);

namespace App\Support\Verification;

final class VerificationReportFingerprint
{
    /**
     * @param  array<int, array<string, mixed>>  $checks
     */
    public static function forChecks(array $checks): string
    {
        $tuples = [];

        foreach ($checks as $check) {
            if (! is_array($check)) {
                continue;
            }

            $key = self::normalizeKey($check['key'] ?? null);
            $status = self::normalizeEnumString($check['status'] ?? null);
            $reasonCode = self::normalizeEnumString($check['reason_code'] ?? null);

            $blocking = is_bool($check['blocking'] ?? null) ? (bool) $check['blocking'] : false;

            $severity = $check['severity'] ?? null;
            $severity = is_string($severity) ? trim($severity) : '';

            if ($severity === '') {
                $severity = '';
            } else {
                $severity = strtolower($severity);
            }

            $tuples[] = [
                'key' => $key,
                'tuple' => implode('|', [
                    $key,
                    $status,
                    $blocking ? '1' : '0',
                    $reasonCode,
                    $severity,
                ]),
            ];
        }

        usort($tuples, static function (array $a, array $b): int {
            $keyComparison = $a['key'] <=> $b['key'];

            if ($keyComparison !== 0) {
                return $keyComparison;
            }

            return $a['tuple'] <=> $b['tuple'];
        });

        $payload = implode("\n", array_map(static fn (array $item): string => (string) $item['tuple'], $tuples));

        return hash('sha256', $payload);
    }

    /**
     * @param  array<string, mixed>  $report
     */
    public static function forReport(array $report): string
    {
        $checks = $report['checks'] ?? null;
        $checks = is_array($checks) ? $checks : [];

        /** @var array<int, array<string, mixed>> $checks */
        return self::forChecks($checks);
    }

    private static function normalizeKey(mixed $value): string
    {
        if (! is_string($value)) {
            return '';
        }

        $value = trim($value);

        return $value === '' ? '' : $value;
    }

    private static function normalizeEnumString(mixed $value): string
    {
        if (! is_string($value)) {
            return '';
        }

        $value = trim($value);

        return $value === '' ? '' : strtolower($value);
    }
}
