<?php

declare(strict_types=1);

namespace App\Services\Intune;

use Illuminate\Support\Str;
use RuntimeException;

final class SecretFingerprintHasher
{
    public function fingerprint(int $workspaceId, string $sourceBucket, string $jsonPointer, mixed $secretValue): string
    {
        if ($workspaceId <= 0) {
            throw new RuntimeException('Workspace-scoped secret fingerprinting requires a valid workspace ID.');
        }

        $payload = implode('|', [
            trim($sourceBucket),
            trim($jsonPointer),
            $this->normalizeSecretValue($secretValue),
        ]);

        return hash_hmac('sha256', $payload, $this->workspaceKey($workspaceId));
    }

    private function workspaceKey(int $workspaceId): string
    {
        $appKey = (string) config('app.key', '');

        if ($appKey === '') {
            throw new RuntimeException('App key is required for secret fingerprinting.');
        }

        if (Str::startsWith($appKey, 'base64:')) {
            $decoded = base64_decode(Str::after($appKey, 'base64:'), true);

            if ($decoded !== false) {
                $appKey = $decoded;
            }
        }

        return hash_hmac('sha256', 'policy-version-secret-fingerprints|'.$workspaceId, $appKey, true);
    }

    private function normalizeSecretValue(mixed $secretValue): string
    {
        $normalized = $this->normalizeValue($secretValue);

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

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

        if (array_is_list($value)) {
            return array_map(fn (mixed $item): mixed => $this->normalizeValue($item), $value);
        }

        ksort($value);

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

        return $value;
    }
}
