<?php

declare(strict_types=1);

namespace App\Framework\Webhook\Security\Providers;

use App\Framework\Core\ValueObjects\HashAlgorithm;
use App\Framework\Encryption\HmacService;
use App\Framework\Webhook\ValueObjects\WebhookSignature;
use InvalidArgumentException;

/**
 * Stripe-specific signature provider
 * Handles Stripe's webhook signature format with timestamp validation
 */
final readonly class StripeSignatureProvider implements SignatureProvider
{
    private const TOLERANCE_SECONDS = 300; // 5 minutes

    public function __construct(
        private HmacService $hmacService,
        private int $tolerance = self::TOLERANCE_SECONDS
    ) {
    }

    public function verify(string $payload, string $signatureHeader, string $secret): bool
    {
        $parts = $this->parseStripeHeader($signatureHeader);

        $timestamp = $parts['t'] ?? 0;
        $signature = $parts['v1'] ?? '';

        // Check timestamp tolerance
        if (abs(time() - $timestamp) > $this->tolerance) {
            return false;
        }

        // Verify signature
        $signedPayload = $timestamp . '.' . $payload;

        return $this->hmacService->verifyHmacString(
            $signedPayload,
            $signature,
            $secret,
            HashAlgorithm::SHA256
        );
    }

    public function parseSignature(string $headerValue): WebhookSignature
    {
        return WebhookSignature::fromStripeHeader($headerValue);
    }

    public function generateSignature(string $payload, string $secret): string
    {
        $timestamp = time();
        $signedPayload = $timestamp . '.' . $payload;

        $hash = $this->hmacService->generateHmac($signedPayload, $secret, HashAlgorithm::SHA256);

        return "t={$timestamp},v1=" . $hash->toString();
    }

    public function getSignatureHeader(): string
    {
        return 'Stripe-Signature';
    }

    public function getProviderName(): string
    {
        return 'stripe';
    }

    private function parseStripeHeader(string $signatureHeader): array
    {
        $parts = [];

        foreach (explode(',', $signatureHeader) as $part) {
            if (str_contains($part, '=')) {
                [$key, $value] = explode('=', $part, 2);
                $parts[$key] = $value;
            }
        }

        if (empty($parts['v1'])) {
            throw new InvalidArgumentException('Invalid Stripe signature format: missing v1 signature');
        }

        return $parts;
    }
}
