<?php

namespace App\Services;

use App\Models\PushNotificationLog;
use App\Notifications\Push\BasePushNotification;
use App\Notifications\Push\Cliente\Contextual\ContextualSegundaPush;
use App\Notifications\Push\Cliente\Contextual\ContextualSextaPush;
use App\Notifications\Push\Cliente\Contextual\ContextualVisitaPush;
use App\Notifications\Push\Cliente\Educativo\Educativo1Push;
use App\Notifications\Push\Cliente\Educativo\Educativo2Push;
use App\Notifications\Push\Cliente\Educativo\Educativo3Push;
use App\Notifications\Push\Cliente\Educativo\Educativo4Push;
use App\Notifications\Push\Cliente\EducativoConversao\EducativoConversao1Push;
use App\Notifications\Push\Cliente\EducativoConversao\EducativoConversao2Push;
use App\Notifications\Push\Cliente\Marketing\Marketing1Push;
use App\Notifications\Push\Cliente\Marketing\Marketing2Push;
use App\Notifications\Push\Cliente\Marketing\Marketing3Push;
use App\Notifications\Push\Cliente\Marketing\Marketing4Push;
use App\Notifications\Push\Cliente\Motivacional\Motivacional1Push as ClienteMotivacional1Push;
use App\Notifications\Push\Cliente\Motivacional\Motivacional2Push as ClienteMotivacional2Push;
use App\Notifications\Push\Cliente\Motivacional\Motivacional3Push as ClienteMotivacional3Push;
use App\Notifications\Push\Cliente\Recorrencia\Recorrencia1Push;
use App\Notifications\Push\Cliente\Recorrencia\Recorrencia2Push;
use App\Notifications\Push\Cliente\Recorrencia\Recorrencia3Push;
use App\Notifications\Push\Cliente\SocialProof\SocialProof1Push;
use App\Notifications\Push\Cliente\SocialProof\SocialProof2Push;
use App\Notifications\Push\Prestador\Motivacional\Motivacional1Push as PrestadorMotivacional1Push;
use App\Notifications\Push\Prestador\ReforcoEducativo\ReforcoEducativo1Push;
use App\Notifications\Push\Prestador\ReforcoEducativo\ReforcoEducativo2Push;
use Illuminate\Support\Collection;

class PushNotificationDispatcher
{
    public function __construct(private PushNotificationService $pushService) {}

    /**
     * Lista central de todas as notificações registradas.
     * Para adicionar uma nova: basta instanciá-la aqui.
     *
     * @return BasePushNotification[]
     */
    public function all(): array
    {
        return [
            // Prestador
            new ReforcoEducativo1Push,
            new ReforcoEducativo2Push,
            new PrestadorMotivacional1Push,

            // Cliente — Marketing
            new Marketing1Push,
            new Marketing2Push,
            new Marketing3Push,
            new Marketing4Push,

            // Cliente — Recorrência
            new Recorrencia1Push,
            new Recorrencia2Push,
            new Recorrencia3Push,

            // Cliente — Educativo
            new Educativo1Push,
            new Educativo2Push,
            new Educativo3Push,
            new Educativo4Push,

            // Cliente — Educativo + Conversão
            new EducativoConversao1Push,
            new EducativoConversao2Push,

            // Cliente — Social Proof
            new SocialProof1Push,
            new SocialProof2Push,

            // Cliente — Motivacional
            new ClienteMotivacional1Push,
            new ClienteMotivacional2Push,
            new ClienteMotivacional3Push,

            // Cliente — Contextual
            new ContextualSextaPush,
            new ContextualSegundaPush,
            new ContextualVisitaPush,
        ];
    }

    /**
     * Processa todas as notificações: aplica cooldowns e envia para elegíveis.
     */
    public function dispatch(): void
    {
        foreach ($this->all() as $notification) {
            $users = $notification->eligibleUsers();

            if ($users->isEmpty()) {
                continue;
            }

            $filtered = $this->applyCooldowns($users, $notification);

            if ($filtered->isEmpty()) {
                continue;
            }

            $this->pushService->sendToUsers($filtered, $notification);
        }
    }

    /**
     * Remove da coleção os usuários que ainda estão em cooldown
     * (tanto de categoria quanto de notificação específica).
     */
    private function applyCooldowns(Collection $users, BasePushNotification $notification): Collection
    {
        $userIds = $users->pluck('id');

        $blockedByCategory = collect();

        if ($notification->categoryCooldownDays() > 0) {
            $blockedByCategory = PushNotificationLog::whereIn('user_id', $userIds)
                ->where('target', $notification->target()->value)
                ->where('category', $notification->category()->value)
                ->where('sent_at', '>=', now()->subDays($notification->categoryCooldownDays()))
                ->pluck('user_id')
                ->unique();
        }

        $blockedByNotification = PushNotificationLog::whereIn('user_id', $userIds)
            ->where('label', $notification->label())
            ->where('sent_at', '>=', now()->subDays($notification->notificationCooldownDays()))
            ->pluck('user_id')
            ->unique();

        $blocked = $blockedByCategory->merge($blockedByNotification)->unique();

        return $users->whereNotIn('id', $blocked)->values();
    }
}
