<?php

namespace App\Domain\Communication\Services;

use App\Domain\Communication\Enums\MessageStatus;
use App\Domain\Communication\Enums\NotificationChannel;
use App\Domain\Communication\Models\NotificationMessage;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Mail;
use Throwable;

/**
 * Hands a queued message to whatever actually carries it.
 *
 * In-app needs no carrier: writing the row is the delivery. Email goes through
 * Laravel's mailer. SMS and WhatsApp are logged until an agency configures a
 * gateway — a message recorded as sent when no gateway exists would be a lie,
 * so those are marked with what happened.
 */
class ChannelDispatcher
{
    public function dispatch(NotificationMessage $message): void
    {
        try {
            match ($message->channel) {
                NotificationChannel::InApp => $this->markSent($message),
                NotificationChannel::Email => $this->email($message),
                NotificationChannel::Sms, NotificationChannel::WhatsApp => $this->gateway($message),
            };
        } catch (Throwable $exception) {
            $message->status = MessageStatus::Failed;
            $message->failure_reason = $exception->getMessage();
            $message->attempts = $message->attempts + 1;
            $message->save();

            Log::error("Notification {$message->uuid} failed: ".$exception->getMessage());
        }
    }

    private function email(NotificationMessage $message): void
    {
        Mail::raw($message->body, function ($mail) use ($message) {
            $mail->to($message->destination, $message->recipient_name)
                ->subject($message->subject_line ?? 'A message from your agency');
        });

        $this->markSent($message);
    }

    private function gateway(NotificationMessage $message): void
    {
        $configured = config("mams.messaging.{$message->channel->value}.enabled", false);

        if (! $configured) {
            $message->status = MessageStatus::Skipped;
            $message->failure_reason = "No {$message->channel->label()} gateway is configured.";
            $message->attempts = $message->attempts + 1;
            $message->save();

            return;
        }

        // An agency plugs its own gateway in here; until then the message is
        // recorded and logged rather than pretended to have been delivered.
        Log::info("[{$message->channel->value}] to {$message->destination}: {$message->body}");

        $this->markSent($message);
    }

    private function markSent(NotificationMessage $message): void
    {
        $message->status = MessageStatus::Sent;
        $message->sent_at = now();
        $message->attempts = $message->attempts + 1;
        $message->save();
    }
}
