<?php

namespace App\Modules\Integrations\Platform\Services;

use App\Modules\Integrations\Platform\Jobs\DeliverWebhookJob;
use App\Modules\Integrations\Platform\Models\IntegrationWebhook;
use App\Modules\Integrations\Platform\Models\IntegrationWebhookDelivery;
use Illuminate\Support\Str;

final class WebhookDeliveryOutcomeHandler
{
    public function __construct(private readonly WebhookStatsUpdater $stats) {}

    public function apply(
        IntegrationWebhookDelivery $delivery,
        IntegrationWebhook $webhook,
        DeliverWebhookJob $job,
        bool $ok,
        ?int $httpStatus,
        string $body,
        ?string $error,
        string $rid,
        int $t0,
    ): void {
        $duration = (int) round((hrtime(true) - $t0) / 1_000_000);
        if ($ok) {
            $delivery->forceFill([
                'status' => 'delivered',
                'response_status' => $httpStatus,
                'response_body' => Str::limit($body, 5000),
                'error' => null,
                'delivered_at' => now(),
                'request_id' => $rid,
                'duration_ms' => $duration,
                'next_retry_at' => null,
            ])->save();
            $this->stats->onDelivered($webhook);

            return;
        }

        $attempts = (int) $delivery->attempt_count;
        if (WebhookRetryPolicy::isExhausted($attempts)) {
            $now = now();
            $delivery->forceFill([
                'status' => 'dead_letter',
                'response_status' => $httpStatus,
                'response_body' => Str::limit($body, 5000),
                'error' => $error !== null ? Str::limit($error, 2000) : null,
                'dead_lettered_at' => $now,
                'exhausted_at' => $now,
                'request_id' => $rid,
                'duration_ms' => $duration,
                'next_retry_at' => null,
            ])->save();
            $this->stats->onDeliveryFailure($webhook, true);

            return;
        }

        $delay = WebhookRetryPolicy::delaySecondsAfterAttempt($attempts);
        $delivery->forceFill([
            'status' => 'failed',
            'response_status' => $httpStatus,
            'response_body' => Str::limit($body, 5000),
            'error' => $error !== null ? Str::limit($error, 2000) : null,
            'request_id' => $rid,
            'duration_ms' => $duration,
            'next_retry_at' => now()->addSeconds($delay),
        ])->save();
        $this->stats->onDeliveryFailure($webhook, false);
        $job->release($delay);
    }
}
