<?php

namespace App\Jobs;

use App\Models\NotificationLog;
use App\Models\User;
use App\Models\UserNotificationPreference;
use App\Notifications\FuelPriceAlert;
use App\Services\PlanFeatures;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Queue\Queueable;

/**
 * Resolves allowed notification channels for a user and trigger, dispatches
 * the FuelPriceAlert notification (which fans out to email + push + WhatsApp +
 * SMS), and logs every outcome (sent, daily_limit, tier_restricted).
 */
final class DispatchUserNotificationJob implements ShouldQueue
{
    use Queueable;

    /** @var string[] */
    private const array ALL_CHANNELS = ['email', 'push', 'whatsapp', 'sms'];

    public function __construct(
        public readonly User $user,
        public readonly string $triggerType,
        public readonly string $fuelType,
        public readonly ?float $price = null,
    ) {
        $this->onQueue('notifications');
    }

    public function handle(): void
    {
        $features = PlanFeatures::for($this->user);

        // Step 3: channels that pass tier + user-pref + daily-limit checks
        $allowed = $features->channelsFor($this->triggerType);

        // Step 4: dispatch the multi-channel notification — Laravel fans out
        // to mail / OneSignal / Vonage WhatsApp / Vonage SMS based on via().
        if ($allowed !== []) {
            $this->user->notify(new FuelPriceAlert(
                $this->triggerType,
                $this->fuelType,
                $this->price,
                $allowed,
            ));
        }

        // Step 5: log a sent entry per allowed channel. The notify() call
        // above queues per-channel sends; per-channel HTTP outcomes are
        // captured in api_logs by the channel adapters themselves.
        foreach ($allowed as $channel) {
            $this->log($channel, sent: true);
        }

        // Channels not in the allowed set — split into missed reasons
        $notAllowed = array_diff(self::ALL_CHANNELS, $allowed);

        foreach ($notAllowed as $channel) {
            if (! $this->userHasEnabledPref($channel)) {
                // User intentionally disabled — do not log (noise)
                continue;
            }

            if ($features->canUseChannel($channel)) {
                // Step 5: tier allows but daily limit exhausted
                $this->log($channel, sent: false, missedReason: 'daily_limit');
            } else {
                // Step 6: tier does not allow the channel the user wanted
                $this->log($channel, sent: false, missedReason: 'tier_restricted');
            }
        }
    }

    private function log(string $channel, bool $sent, ?string $missedReason = null): void
    {
        NotificationLog::create([
            'user_id' => $this->user->id,
            'channel' => $channel,
            'trigger_type' => $this->triggerType,
            'fuel_type' => $this->fuelType,
            'price' => $this->price,
            'sent' => $sent,
            'missed_reason' => $missedReason,
            'created_at' => now(),
        ]);
    }

    private function userHasEnabledPref(string $channel): bool
    {
        return UserNotificationPreference::where('user_id', $this->user->id)
            ->where('channel', $channel)
            ->where('enabled', true)
            ->exists();
    }
}
