<?php

declare(strict_types=1);

namespace CpCreation\VitiCore\Monitoring\External\Message;

use CpCreation\VitiCore\Commerce\Catalog\CatalogContract;
use CpCreation\VitiCore\Commerce\Catalog\Outbox\CatalogWebhookSigner;
use CpCreation\VitiCore\Monitoring\Error\ErrorMonitoringConfiguration;
use Symfony\Component\Messenger\Attribute\AsMessageHandler;
use Symfony\Component\Messenger\Exception\UnrecoverableMessageHandlingException;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;

#[AsMessageHandler]
final readonly class DeliverExternalConnectionHealthMessageHandler
{
    public function __construct(
        private ErrorMonitoringConfiguration $configuration,
        private CatalogWebhookSigner $signer,
        private HttpClientInterface $httpClient,
    ) {}

    public function __invoke(DeliverExternalConnectionHealthMessage $message): void
    {
        if (!$this->configuration->isReady()) {
            return;
        }

        try {
            $body = json_encode($message->payload, \JSON_THROW_ON_ERROR | \JSON_UNESCAPED_SLASHES);
        } catch (\JsonException $exception) {
            throw new UnrecoverableMessageHandlingException('L’état de connexion externe ne peut pas être sérialisé.', previous: $exception);
        }

        $timestamp = (string) time();
        $eventId = \is_string($message->payload['event_id'] ?? null) ? $message->payload['event_id'] : '';
        $instanceId = $this->configuration->instanceId();

        try {
            $statusCode = $this->httpClient->request('POST', $this->configuration->endpointUrl('external-connections'), [
                'body' => $body,
                'headers' => [
                    'Content-Type' => 'application/json',
                    'User-Agent' => CatalogContract::USER_AGENT,
                    'Idempotency-Key' => $eventId,
                    'X-Serenity-Timestamp' => $timestamp,
                    'X-Serenity-Instance' => $instanceId,
                    'X-Serenity-Event-Id' => $eventId,
                    'X-Serenity-Signature' => $this->signer->sign($this->configuration->secret(), $timestamp, $body),
                ],
                'timeout' => 10,
                'max_duration' => 15,
                'max_redirects' => 0,
            ])->getStatusCode();
        } catch (TransportExceptionInterface $exception) {
            throw new \RuntimeException('Erreur réseau pendant la remontée de l’état de connexion externe.', previous: $exception);
        }

        if ($statusCode >= 200 && $statusCode < 300) {
            return;
        }

        $error = \sprintf('Le hub a refusé l’état de connexion externe avec le statut HTTP %d.', $statusCode);
        if ($statusCode >= 500 || \in_array($statusCode, [408, 425, 429], true)) {
            throw new \RuntimeException($error);
        }

        throw new UnrecoverableMessageHandlingException($error);
    }
}
