<?php

namespace App\Jobs;

use App\Actions\FetchFeedArticlesAction;
use App\Enums\ActivityTypeEnum;
use App\Enums\NotificationSeverityEnum;
use App\Enums\NotificationTypeEnum;
use App\Events\ActivityLogged;
use App\Models\Feed;
use App\Models\Notification;
use App\Services\Log\LogSaver;
use App\Services\Notification\NotificationService;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Queue\Queueable;

class ArticleDiscoveryForFeedJob implements ShouldQueue
{
    use Queueable;

    private const FEED_DISCOVERY_DELAY_MINUTES = 5;

    public function __construct(
        private readonly Feed $feed
    ) {
        $this->onQueue('feed-discovery');
    }

    public function handle(LogSaver $logSaver, FetchFeedArticlesAction $fetchFeedArticles, NotificationService $notificationService): void
    {
        $logSaver->info('Starting feed article fetch', null, [
            'feed_id' => $this->feed->id,
            'feed_name' => $this->feed->name,
            'feed_url' => $this->feed->url,
        ]);

        $articles = $fetchFeedArticles->execute($this->feed);

        $logSaver->info('Feed article fetch completed', null, [
            'feed_id' => $this->feed->id,
            'feed_name' => $this->feed->name,
            'articles_count' => $articles->count(),
        ]);

        $this->feed->update(['last_fetched_at' => now()]);

        if ($articles->isEmpty()) {
            ActivityLogged::dispatch(
                ActivityTypeEnum::ERROR,
                "{$this->feed->name} returned no articles",
                ['articles_count' => 0],
                $this->feed,
            );

            $this->warnFeedReturnedNothing($notificationService);

            return;
        }

        ActivityLogged::dispatch(
            ActivityTypeEnum::FETCH,
            "Fetched {$articles->count()} articles from {$this->feed->name}",
            ['articles_count' => $articles->count()],
            $this->feed,
        );
    }

    private function warnFeedReturnedNothing(NotificationService $notificationService): void
    {
        $alreadyNotified = Notification::query()
            ->where('type', NotificationTypeEnum::FEED_EMPTY)
            ->where('notifiable_type', $this->feed->getMorphClass())
            ->where('notifiable_id', $this->feed->getKey())
            ->unread()
            ->exists();

        if ($alreadyNotified) {
            return;
        }

        $notificationService->send(
            type: NotificationTypeEnum::FEED_EMPTY,
            severity: NotificationSeverityEnum::WARNING,
            title: "Feed \"{$this->feed->name}\" returned no articles",
            message: "The fetch completed but produced nothing. Check that {$this->feed->url} is still a valid feed.",
            notifiable: $this->feed,
        );
    }

    public static function dispatchForAllActiveFeeds(): void
    {
        $logSaver = app(LogSaver::class);

        Feed::where('is_active', true)
            ->get()
            ->each(function (Feed $feed, $index) use ($logSaver) {
                // Space jobs apart to avoid overwhelming feeds
                $delayMinutes = $index * self::FEED_DISCOVERY_DELAY_MINUTES;

                self::dispatch($feed)
                    ->delay(now()->addMinutes($delayMinutes))
                    ->onQueue('feed-discovery');

                $logSaver->info('Dispatched feed discovery job', null, [
                    'feed_id' => $feed->id,
                    'feed_name' => $feed->name,
                    'delay_minutes' => $delayMinutes,
                ]);
            });
    }
}
