<?php

declare(strict_types=1);

namespace App\Services\NovaCards;

use App\Jobs\NovaCards\RenderNovaCardPreviewJob;
use App\Models\NovaCard;
use App\Services\NovaCards\NovaCardPublishModerationService;
use Illuminate\Support\Carbon;
use InvalidArgumentException;

class NovaCardPublishService
{
    public function __construct(
        private readonly NovaCardRenderService $renderService,
        private readonly NovaCardVersionService $versions,
        private readonly NovaCardPublishModerationService $moderation,
    ) {
    }

    public function queuePublish(NovaCard $card): NovaCard
    {
        $card->forceFill([
            'status' => NovaCard::STATUS_PROCESSING,
            'moderation_status' => NovaCard::MOD_PENDING,
            'published_at' => $card->published_at ?? Carbon::now(),
            'scheduled_for' => null,
            'scheduling_timezone' => null,
            'render_version' => (int) $card->render_version + 1,
        ])->save();

        RenderNovaCardPreviewJob::dispatch($card->id)
            ->onQueue((string) config('nova_cards.render.queue', 'default'));

        return $card->refresh();
    }

    public function publishNow(NovaCard $card): NovaCard
    {
        $card->forceFill([
            'status' => NovaCard::STATUS_PROCESSING,
            'moderation_status' => NovaCard::MOD_PENDING,
            'published_at' => $card->published_at ?? Carbon::now(),
            'scheduled_for' => null,
            'scheduling_timezone' => null,
            'render_version' => (int) $card->render_version + 1,
        ])->save();

        $this->renderService->render($card->refresh());

        $evaluation = $this->moderation->evaluate($card->fresh()->loadMissing(['originalCard.user', 'rootCard.user']));

        $card = $this->moderation->applyPublishOutcome($card->fresh(), $evaluation);

        $this->versions->snapshot($card->refresh()->loadMissing('template'), $card->user, 'Published version', true);

        return $card->refresh()->load(['category', 'template', 'tags', 'backgroundImage']);
    }

    public function schedule(NovaCard $card, Carbon $scheduledFor, ?string $timezone = null): NovaCard
    {
        $scheduledFor = $scheduledFor->copy()->utc();

        if ($scheduledFor->lte(now()->addMinute())) {
            throw new InvalidArgumentException('Scheduled publish time must be at least 1 minute in the future.');
        }

        $card->forceFill([
            'status' => NovaCard::STATUS_SCHEDULED,
            'scheduled_for' => $scheduledFor,
            'published_at' => $scheduledFor,
            'scheduling_timezone' => $timezone,
        ])->save();

        return $card->refresh()->load(['category', 'template', 'tags', 'backgroundImage']);
    }

    public function clearSchedule(NovaCard $card): NovaCard
    {
        $card->forceFill([
            'status' => NovaCard::STATUS_DRAFT,
            'scheduled_for' => null,
            'published_at' => null,
        ])->save();

        return $card->refresh()->load(['category', 'template', 'tags', 'backgroundImage']);
    }
}
