<?php

namespace App\Notifications;

use App\Notifications\Channels\OneSignalChannel;
use App\Notifications\Channels\VonageSmsChannel;
use App\Notifications\Channels\VonageWhatsAppChannel;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;

/**
 * Multi-channel fuel price alert. The dispatching job already filters channels
 * by tier, user preference, and daily limit — `via()` returns exactly that
 * filtered set. The notification is queued so individual channel sends don't
 * block the dispatch job.
 *
 * Channel keys map to:
 *   'email'    → mail (Laravel built-in)
 *   'push'     → OneSignalChannel
 *   'whatsapp' → VonageWhatsAppChannel
 *   'sms'      → VonageSmsChannel
 */
final class FuelPriceAlert extends Notification implements ShouldQueue
{
    use Queueable;

    /** @var array<string, class-string> */
    private const array CHANNEL_MAP = [
        'email' => 'mail',
        'push' => OneSignalChannel::class,
        'whatsapp' => VonageWhatsAppChannel::class,
        'sms' => VonageSmsChannel::class,
    ];

    /** @param  string[]  $channels  Pre-filtered channel keys ('email', 'push', 'whatsapp', 'sms') */
    public function __construct(
        public readonly string $triggerType,
        public readonly string $fuelType,
        public readonly ?float $price,
        public readonly array $channels,
    ) {
        $this->onQueue('notifications');
    }

    /** @return array<int, string> */
    public function via(mixed $notifiable): array
    {
        return array_values(array_map(
            fn (string $key) => self::CHANNEL_MAP[$key] ?? $key,
            $this->channels,
        ));
    }

    public function toMail(mixed $notifiable): MailMessage
    {
        return (new MailMessage)
            ->subject($this->headline())
            ->greeting("Hi {$notifiable->name},")
            ->line($this->body())
            ->action('Open FuelAlert', route('dashboard'))
            ->line('You can change which alerts you receive in your account settings.');
    }

    /** @return array{heading: string, message: string} */
    public function toOneSignal(mixed $notifiable): array
    {
        return [
            'heading' => $this->headline(),
            'message' => $this->body(),
        ];
    }

    public function toVonageWhatsApp(mixed $notifiable): string
    {
        return $this->shortBody();
    }

    public function toVonageSms(mixed $notifiable): string
    {
        return $this->shortBody();
    }

    private function headline(): string
    {
        return match ($this->triggerType) {
            'price_threshold' => 'Price hit your threshold',
            'score_change' => 'Fill-up signal changed',
            'scheduled_morning' => 'Morning fuel update',
            'scheduled_evening' => 'Evening fuel update',
            default => 'Fuel alert',
        };
    }

    private function body(): string
    {
        $fuel = strtoupper($this->fuelType);
        $price = $this->price !== null ? number_format($this->price, 1).'p' : null;

        return match ($this->triggerType) {
            'price_threshold' => $price !== null
                ? "{$fuel} dropped to {$price} near you."
                : "{$fuel} hit your alert threshold.",
            'score_change' => "The {$fuel} fill-up score has changed near you.",
            'scheduled_morning', 'scheduled_evening' => "Latest {$fuel} update is ready in your dashboard.",
            default => "There's a new {$fuel} alert for you.",
        };
    }

    /** SMS/WhatsApp must stay short — single line, ~160 chars max. */
    private function shortBody(): string
    {
        return $this->headline().': '.$this->body();
    }
}
