<?php

namespace App\Notifications;

use App\Models\AppNotification;
use App\Models\MessageLog;
use App\Models\User;
use App\Notifications\Contracts\ChannelDriver;

/**
 * Sends an OutgoingMessage across the configured channels in order
 * (e.g. WhatsApp first, then SMS) until one succeeds, recording the attempt
 * in message_logs for the admin.
 */
class MessageDispatcher
{
    public function send(OutgoingMessage $message): MessageLog
    {
        $attempts = [];
        $success  = null;

        foreach ($this->channelOrder() as $channel) {
            $driver = $this->driver($channel);
            if (! $driver) {
                continue;
            }
            if (! $driver->isConfigured()) {
                $attempts[] = ['channel' => $channel, 'ok' => false, 'error' => 'not configured'];
                continue;
            }

            $result = $driver->send($message);
            $attempts[] = ['channel' => $channel, 'ok' => $result->success, 'error' => $result->error];

            if ($result->success) {
                $success = $result;
                break;
            }
        }

        $this->recordInApp($message);

        return MessageLog::create([
            'to'                  => $message->to,
            'type'                => $message->type,
            'channel'             => $success?->channel ?? ($attempts ? end($attempts)['channel'] : null),
            'status'              => $success ? 'sent' : 'failed',
            'text'                => $message->text,
            'template'            => $message->template,
            'provider_message_id' => $success?->providerMessageId,
            'error'               => $success ? null : collect($attempts)->pluck('error')->filter()->implode(' | '),
            'attempts'            => $attempts,
        ]);
    }

    /**
     * Drop an entry in the customer's in-app notifications feed (the bell inbox).
     * OTPs are excluded — they don't belong in a history. Best-effort: a feed
     * failure must never break the actual send.
     */
    private function recordInApp(OutgoingMessage $message): void
    {
        if ($message->type === 'otp') {
            return;
        }
        try {
            $user = User::where('phone', $message->to)->first();
            if (! $user) {
                return;
            }
            AppNotification::create([
                'notifiable_type' => User::class,
                'notifiable_id'   => $user->id,
                'type'            => $message->type,
                'data'            => [
                    'title' => ucwords(str_replace('_', ' ', $message->type)),
                    'body'  => $message->text,
                ],
            ]);
        } catch (\Throwable $e) {
            // ignore — the in-app feed is non-critical
        }
    }

    /** @return string[] e.g. ['whatsapp','sms'] or ['log'] */
    private function channelOrder(): array
    {
        return array_values(array_filter(array_map('trim', explode(',', (string) config('notifications.channels', 'log')))));
    }

    private function driver(string $channel): ?ChannelDriver
    {
        $class = config("notifications.drivers.$channel.class");
        return $class ? app($class) : null;
    }
}
