<?php

declare(strict_types=1);

namespace App\Framework\Http;

/**
 * Repräsentiert eine kryptografisch sichere und signierte Request-ID.
 * Enthält sowohl die ID selbst als auch deren HMAC-Signatur zur Validierung.
 */
final readonly class RequestId
{
    private string $id;

    private string $signature;

    private string $combined;

    /**
     * Erstellt eine neue Request-ID oder parsed eine bestehende
     *
     * @param string|null $combined Wenn nicht null, wird diese ID validiert und verwendet
     * @param string $secret Das Secret für die HMAC-Signatur
     */
    public function __construct(?string $combined = null, string $secret = '')
    {
        // Secret über eine Umgebungsvariable beziehen, falls nicht angegeben
        $secret = $secret ?: ($_ENV['APP_SECRET'] ?? 'default-secret-change-me');

        if ($combined !== null && self::isValidFormat($combined)) {
            // Bestehende ID parsen
            [$rawId, $signature] = explode('.', $combined, 2);

            // Signatur validieren
            $expectedSignature = $this->generateSignature($rawId, $secret);

            if (! hash_equals($expectedSignature, $signature)) {
                // Bei ungültiger Signatur, neue ID erstellen
                $this->generateNew($secret);
            } else {
                // Bei gültiger Signatur, diese ID verwenden
                $this->id = $rawId;
                $this->signature = $signature;
                $this->combined = $combined;
            }
        } else {
            // Neue ID erstellen
            $this->generateNew($secret);
        }
    }

    /**
     * Generiert eine neue Request-ID mit Signatur
     */
    private function generateNew(string $secret): void
    {
        // Zufällige ID generieren (16 Byte = 32 Hex-Zeichen)
        $this->id = bin2hex(random_bytes(16));

        // Signatur erstellen
        $this->signature = $this->generateSignature($this->id, $secret);

        // Kombinierte Darstellung erstellen
        $this->combined = $this->id . '.' . $this->signature;
    }

    /**
     * Generiert eine HMAC-Signatur für die ID
     */
    private function generateSignature(string $id, string $secret): string
    {
        return hash_hmac('sha256', $id, $secret, false);
    }

    /**
     * Prüft, ob eine kombinierte ID das korrekte Format hat
     */
    private static function isValidFormat(string $combined): bool
    {
        // Format: 32 Hex-Zeichen + Punkt + 64 Hex-Zeichen (SHA-256 HMAC)
        return preg_match('/^[a-f0-9]{32}\.[a-f0-9]{64}$/i', $combined) === 1;
    }

    /**
     * Gibt die kombinierte ID (ID + Signatur) zurück
     */
    public function toString(): string
    {
        return $this->combined;
    }

    /**
     * Gibt nur die eigentliche ID ohne Signatur zurück
     */
    public function getId(): string
    {
        return $this->id;
    }

    /**
     * Gibt die Signatur zurück
     */
    public function getSignature(): string
    {
        return $this->signature;
    }

    /**
     * String-Repräsentation für Debugging
     */
    public function __toString(): string
    {
        return $this->toString();
    }
}
