<?php

namespace App\Jobs;

use App\Models\PushSubscription;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Queue\Queueable;
use Illuminate\Support\Facades\Log;
use Minishlink\WebPush\Subscription;
use Minishlink\WebPush\WebPush;
use Throwable;

class SendWebPushJob implements ShouldQueue
{
    use Queueable;

    /**
     * @param  array<string,mixed>  $payload
     */
    public function __construct(private readonly int $subscriptionId, private readonly array $payload) {}

    public function handle(): void
    {
        $subscription = PushSubscription::query()->find($this->subscriptionId);
        if ($subscription === null) {
            return;
        }

        $auth = config('webpush.vapid');
        if (! is_array($auth) || empty($auth['public_key']) || empty($auth['private_key']) || empty($auth['subject'])) {
            Log::notice('webpush.skipped_missing_vapid');

            return;
        }

        try {
            $webPush = new WebPush(['VAPID' => [
                'subject' => (string) $auth['subject'],
                'publicKey' => (string) $auth['public_key'],
                'privateKey' => (string) $auth['private_key'],
            ]]);
        } catch (Throwable $e) {
            Log::error('webpush.invalid_vapid_config', [
                'message' => $e->getMessage(),
            ]);

            return;
        }

        $encoding = strtolower(trim((string) ($subscription->content_encoding ?: 'aesgcm')));
        if (! in_array($encoding, ['aesgcm', 'aes128gcm'], true)) {
            $encoding = 'aesgcm';
        }

        $webPushSubscription = Subscription::create([
            'endpoint' => $subscription->endpoint,
            'keys' => [
                'p256dh' => $subscription->public_key,
                'auth' => $subscription->auth_token,
            ],
            'contentEncoding' => $encoding,
        ]);

        try {
            $webPush->queueNotification($webPushSubscription, json_encode($this->payload, JSON_UNESCAPED_UNICODE));
        } catch (Throwable $e) {
            Log::error('webpush.queue_failed', [
                'subscription_id' => $subscription->id,
                'message' => $e->getMessage(),
            ]);

            return;
        }

        foreach ($webPush->flush() as $report) {
            if (! $report->isSuccess()) {
                $status = $report->getResponse()?->getStatusCode();
                $body = $report->getResponseContent();
                Log::warning('webpush.delivery_failed', [
                    'subscription_id' => $subscription->id,
                    'endpoint' => $subscription->endpoint,
                    'reason' => $report->getReason(),
                    'http_status' => $status,
                    'response_excerpt' => $body !== null && $body !== '' ? mb_substr($body, 0, 500) : null,
                ]);

                if ($report->isSubscriptionExpired()) {
                    $subscription->delete();
                }
            }
        }
    }
}
