<?php

namespace App\Jobs;

use App\Models\Event;
use App\Models\TenantAdminPushSubscription;
use App\Models\TenantNotificationLog;
use App\Services\Push\AdminWebPushDispatcher;
use App\Services\TenantAdminPushSubscriptionService;
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\Arr;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;

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

    public function __construct(public int $notificationLogId)
    {
        $this->onQueue('notifications');
    }

    /**
     * Execute the job.
     */
    public function handle(
        AdminWebPushDispatcher $dispatcher,
        TenantAdminPushSubscriptionService $subscriptions
    ): void {
        if (! config('push.enabled')) {
            return;
        }

        $notification = TenantNotificationLog::query()->find($this->notificationLogId);

        if (! $notification) {
            return;
        }

        $targets = TenantAdminPushSubscription::query()
            ->where('tenant_id', $notification->tenant_id)
            ->where('status', 'active')
            ->get();

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

        $context = $notification->context ?? [];
        $eventId = Arr::get($context, 'event_id') ?? Arr::get($context, 'eventId');
        $event = $eventId ? Event::query()->select(['id', 'name', 'slug'])->find($eventId) : null;
        $eventName = $this->resolveEventName($event?->name);

        $title = $eventName
            ? sprintf('%s · %s', $eventName, Str::headline(str_replace('_', ' ', $notification->type)))
            : Str::headline(str_replace('_', ' ', $notification->type));

        $payload = [
            'title' => $title,
            'body' => $notification->status === 'failed'
                ? ($notification->failure_reason ?: 'Benachrichtigung fehlgeschlagen')
                : 'Neue Admin-Benachrichtigung',
            'data' => [
                'notification_id' => $notification->id,
                'event_id' => $event?->id,
                'url' => "/event-admin/mobile/notifications/{$notification->id}",
            ],
        ];

        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('Admin web push delivery failed', [
                    'subscription_id' => $target->id,
                    'tenant_id' => $notification->tenant_id,
                    'reason' => $exception->getMessage(),
                ]);

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

    private function resolveEventName(mixed $name): ?string
    {
        if (is_string($name)) {
            return $name;
        }

        if (is_array($name)) {
            foreach ($name as $value) {
                if (is_string($value) && $value !== '') {
                    return $value;
                }
            }
        }

        return null;
    }
}
