<?php
declare(strict_types=1);

function attestationBase64UrlEncode(string $value): string
{
    return rtrim(strtr(base64_encode($value), "+/", "-_"), "=");
}

function attestationBase64UrlDecode(string $value): string|false
{
    $value = strtr($value, "-_", "+/");
    $padding = strlen($value) % 4;
    if ($padding > 0) {
        $value .= str_repeat("=", 4 - $padding);
    }

    return base64_decode($value, true);
}

function attestationSigningSecret(): string
{
    static $secret = null;

    if (is_string($secret) && $secret !== "") {
        return $secret;
    }

    $envSecret = trim((string) getenv("PIS_ATTESTATION_SECRET"));
    if ($envSecret !== "") {
        $secret = $envSecret;
        return $secret;
    }

    $configHash = @sha1_file(__DIR__ . "/../config/database.php");
    $serverHint = (string) ($_SERVER["HTTP_HOST"] ?? "localhost");
    $secret = hash("sha256", $configHash . "|PIS|attestation|" . $serverHint);

    return $secret;
}

function attestationSignPayload(string $encodedPayload): string
{
    if ($encodedPayload === "") {
        return "";
    }

    $signature = hash_hmac("sha256", $encodedPayload, attestationSigningSecret(), true);

    return attestationBase64UrlEncode($signature);
}

function attestationVerifySignature(string $encodedPayload, string $signature): bool
{
    if ($encodedPayload === "" || $signature === "") {
        return false;
    }

    $expected = attestationSignPayload($encodedPayload);

    return $expected !== "" && hash_equals($expected, $signature);
}

function attestationEncodePayload(array $payload): string
{
    if ($payload === []) {
        return "";
    }

    $normalized = [];
    foreach ($payload as $key => $value) {
        $normalized[(string) $key] = trim((string) $value);
    }
    ksort($normalized);

    $json = json_encode($normalized, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);

    return is_string($json) ? attestationBase64UrlEncode($json) : "";
}

function attestationDecodePayload(string $encodedPayload): ?array
{
    if ($encodedPayload === "") {
        return null;
    }

    $json = attestationBase64UrlDecode($encodedPayload);
    if (!is_string($json) || $json === "") {
        return null;
    }

    $data = json_decode($json, true);

    return is_array($data) ? $data : null;
}
