<?php

namespace App\Jobs;

use App\Models\GuestNotification;
use App\Models\PushSubscription;
use App\Services\Push\WebPushDispatcher;
use App\Services\PushSubscriptionService;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;

class SendGuestPushNotificationBatch implements ShouldQueue
{
    use Dispatchable;
    use InteractsWithQueue;
    use Queueable;
    use SerializesModels;

    /**
     * @param  int[]  $subscriptionIds
     */
    public function __construct(
        public int $notificationId,
        public array $subscriptionIds
    ) {
        $this->onQueue('notifications');
    }

    public function handle(
        WebPushDispatcher $dispatcher,
        PushSubscriptionService $subscriptions
    ): void {
        if (! config('push.enabled')) {
            return;
        }

        /** @var GuestNotification|null $notification */
        $notification = GuestNotification::query()->find($this->notificationId);

        if (! $notification) {
            return;
        }

        /** @var Collection<int, PushSubscription> $targets */
        $targets = PushSubscription::query()
            ->whereIn('id', $this->subscriptionIds)
            ->where('status', 'active')
            ->get();

        if ($targets->isEmpty()) {
            return;
        }

        $payload = [
            'title' => $notification->title,
            'body' => $notification->body,
            'data' => [
                'notification_id' => $notification->id,
                'event_id' => $notification->event_id,
                'type' => $notification->type->value,
                'cta' => $notification->payload['cta'] ?? null,
            ],
        ];

        foreach ($targets as $target) {
            try {
                $report = $dispatcher->send($target, $payload);

                if ($report === null) {
                    continue;
                }

                if ($report->isSuccess()) {
                    $subscriptions->markDelivered($target);

                    continue;
                }

                if ($report->isSubscriptionExpired()) {
                    $target->update(['status' => 'revoked']);
                }

                $subscriptions->markFailed($target, $report->getReason());
            } catch (\Throwable $exception) {
                Log::channel('notifications')->warning('Web push delivery failed', [
                    'subscription_id' => $target->id,
                    'event_id' => $notification->event_id,
                    'reason' => $exception->getMessage(),
                ]);

                $subscriptions->markFailed($target, $exception->getMessage());
            }
        }
    }
}
