<?php

namespace App\Jobs;

use App\Actions\PublishRouteArticleAction;
use App\Enums\ApprovalStatusEnum;
use App\Enums\LogLevelEnum;
use App\Events\ActionPerformed;
use App\Exceptions\PublishException;
use App\Models\ArticlePublication;
use App\Models\RouteArticle;
use App\Models\Setting;
use Illuminate\Contracts\Queue\ShouldBeUnique;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Queue\Queueable;

class PublishNextArticleJob implements ShouldBeUnique, ShouldQueue
{
    use Queueable;

    /**
     * The number of seconds after which the job's unique lock will be released.
     */
    public int $uniqueFor = 300;

    public function __construct()
    {
        $this->onQueue('publishing');
    }

    /**
     * Execute the job.
     *
     * @throws PublishException
     */
    public function handle(PublishRouteArticleAction $publishRouteArticle): void
    {
        if ($this->dailyCapReached()) {
            return;
        }

        $interval = Setting::getArticlePublishingInterval();

        if ($interval > 0) {
            $lastPublishedAt = ArticlePublication::max('published_at');

            if ($lastPublishedAt && now()->diffInMinutes($lastPublishedAt, absolute: true) < $interval) {
                return;
            }
        }

        // Get the oldest approved route_article that hasn't been published to its channel yet
        $routeArticle = RouteArticle::where('approval_status', ApprovalStatusEnum::APPROVED)
            ->dueForPublishing()
            ->whereDoesntHave('article.articlePublications', function ($query) {
                $query->whereColumn('article_publications.platform_channel_id', 'route_articles.platform_channel_id');
            })
            ->oldest('route_articles.created_at')
            ->with(['article', 'platformChannel.platformInstance', 'platformChannel.activePlatformAccounts'])
            ->first();

        if (! $routeArticle) {
            return;
        }

        $article = $routeArticle->article;

        ActionPerformed::dispatch('Publishing next article from scheduled job', LogLevelEnum::INFO, [
            'article_id' => $article->id,
            'title' => $article->title,
            'url' => $article->url,
            'route' => $routeArticle->feed_id.'-'.$routeArticle->platform_channel_id,
        ]);

        $publishRouteArticle->execute($routeArticle);
    }

    private function dailyCapReached(): bool
    {
        $cap = Setting::getDailyPublishCap();

        if ($cap <= 0) {
            return false;
        }

        return ArticlePublication::where('published_at', '>=', now()->startOfDay())->count() >= $cap;
    }
}
