<?php

declare(strict_types=1);

namespace App\Framework\Webhook\Security;

use App\Framework\Encryption\HmacService;
use App\Framework\Webhook\Security\Providers\GenericHmacProvider;
use App\Framework\Webhook\Security\Providers\GitHubSignatureProvider;
use App\Framework\Webhook\Security\Providers\LegalServiceProvider;
use App\Framework\Webhook\Security\Providers\SignatureProvider;
use App\Framework\Webhook\Security\Providers\StripeSignatureProvider;
use App\Framework\Webhook\Security\Providers\TelegramSignatureProvider;
use App\Framework\Webhook\ValueObjects\WebhookProvider;
use InvalidArgumentException;

/**
 * Multi-provider webhook signature verification service
 * Uses framework's Encryption module and Hash system for secure verification
 */
final class SignatureVerifier
{
    /** @var array<string, SignatureProvider> */
    private array $providers;

    public function __construct(HmacService $hmacService)
    {
        $this->providers = [
            'stripe' => new StripeSignatureProvider($hmacService),
            'github' => new GitHubSignatureProvider($hmacService),
            'legal-service' => new LegalServiceProvider($hmacService),
            'telegram' => new TelegramSignatureProvider(),
            'generic' => new GenericHmacProvider($hmacService),
        ];
    }

    /**
     * Verify webhook signature using appropriate provider
     */
    public function verify(
        string $payload,
        string $signatureHeader,
        string $secret,
        WebhookProvider $provider
    ): bool {
        $signatureProvider = $this->getProvider($provider);

        return $signatureProvider->verify($payload, $signatureHeader, $secret);
    }

    /**
     * Generate signature for outgoing webhooks
     */
    public function generateSignature(
        string $payload,
        string $secret,
        WebhookProvider $provider
    ): string {
        $signatureProvider = $this->getProvider($provider);

        return $signatureProvider->generateSignature($payload, $secret);
    }

    /**
     * Get signature header name for provider
     */
    public function getSignatureHeader(WebhookProvider $provider): string
    {
        $signatureProvider = $this->getProvider($provider);

        return $signatureProvider->getSignatureHeader();
    }

    /**
     * Add custom signature provider
     */
    public function addProvider(string $name, SignatureProvider $provider): void
    {
        $this->providers[$name] = $provider;
    }

    /**
     * Check if provider is supported
     */
    public function hasProvider(WebhookProvider $provider): bool
    {
        return isset($this->providers[$provider->toString()]);
    }

    /**
     * Get all registered provider names
     */
    public function getProviderNames(): array
    {
        return array_keys($this->providers);
    }

    private function getProvider(WebhookProvider $provider): SignatureProvider
    {
        $providerName = $provider->toString();

        if (! isset($this->providers[$providerName])) {
            throw new InvalidArgumentException("Unsupported webhook provider: {$providerName}");
        }

        return $this->providers[$providerName];
    }
}
