<?php

namespace Modules\VetStaffPortal\Services;

use Illuminate\Support\Facades\Log;
use Modules\VetStaffPortal\Entities\VsPushSubscription;

/**
 * Sends Web Push notifications to staff devices via VAPID. Reuses the same
 * VAPID keys as the pet-owner push (config portal_push) — one keypair per
 * server is fine. Wraps minishlink/web-push when present; otherwise no-ops +
 * logs so callers can fire unconditionally.
 *
 *   composer require minishlink/web-push   (to activate real delivery)
 *   php artisan portal:push:keys           (generate VAPID keys, shared)
 */
class StaffPushSender
{
    public function isReady(): bool
    {
        return class_exists(\Minishlink\WebPush\WebPush::class)
            && config('portal_push.public_key')
            && config('portal_push.private_key');
    }

    public function send(VsPushSubscription $sub, array $payload): bool
    {
        if (! $this->isReady()) {
            Log::info('[StaffPush] (no-op — library not installed)', [
                'user_id' => $sub->user_id, 'payload' => $payload,
            ]);
            return true;
        }

        $webPush = new \Minishlink\WebPush\WebPush([
            'VAPID' => [
                'subject'    => config('portal_push.subject'),
                'publicKey'  => config('portal_push.public_key'),
                'privateKey' => config('portal_push.private_key'),
            ],
        ]);

        $report = $webPush->sendOneNotification(
            \Minishlink\WebPush\Subscription::create($sub->toWebPushArray()),
            json_encode($payload, JSON_UNESCAPED_SLASHES),
        );

        if ($report->isSuccess()) {
            $sub->forceFill(['last_used_at' => now(), 'consecutive_failures' => 0])->save();
            return true;
        }

        $status = $report->getResponse()?->getStatusCode();
        if (in_array($status, [404, 410], true)) {
            $sub->delete();               // permanently gone
            return false;
        }

        $sub->forceFill([
            'last_failed_at'       => now(),
            'consecutive_failures' => $sub->consecutive_failures + 1,
        ])->save();
        Log::warning('[StaffPush] Send failed', ['user_id' => $sub->user_id, 'status' => $status]);
        return false;
    }

    /** Send to every subscription a user has for the given category. */
    public function sendToUser(int $userId, string $category, array $payload): int
    {
        $sent = 0;
        foreach (VsPushSubscription::where('user_id', $userId)->get() as $sub) {
            if (! $sub->wantsCategory($category)) continue;
            if ($this->send($sub, $payload)) $sent++;
        }
        return $sent;
    }

    /** Broadcast to all staff devices in a business that opted into the category. */
    public function broadcastToBusiness(int $businessId, string $category, array $payload): int
    {
        $sent = 0;
        VsPushSubscription::where('business_id', $businessId)
            ->chunk(200, function ($subs) use ($category, $payload, &$sent) {
                foreach ($subs as $sub) {
                    if (! $sub->wantsCategory($category)) continue;
                    if ($this->send($sub, $payload)) $sent++;
                }
            });
        return $sent;
    }
}
