<?php

declare(strict_types=1);

namespace Builder\Core\Foundation\Commands;

use Builder\Core\Foundation\Concerns\HasTranslatablePublishing;
use Builder\Core\Foundation\Contracts\HasPublishableRecords;
use Builder\Core\Foundation\Contracts\Publishable;
use Builder\Core\Foundation\Enums\PublicationStatus;
use Builder\Core\Foundation\Registry;
use Illuminate\Console\Command;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model;

final class PublishScheduledContentCommand extends Command
{
    protected $signature = 'builder:publish';

    protected $description = 'Publish all scheduled content that is due.';

    public function handle(Registry $registry): void
    {
        foreach ($registry->resources() as $resourceClass) {
            $resource = new $resourceClass;

            if (! $resource instanceof HasPublishableRecords) {
                continue;
            }

            /** @var class-string<Model> $modelClass */
            $modelClass = $resourceClass::getModel();

            if (in_array(HasTranslatablePublishing::class, class_uses_recursive($modelClass))) {
                $this->publishTranslations($resourceClass, $modelClass);
            } else {
                $this->publishRecords($resourceClass, $modelClass);
            }
        }
    }

    /** @param class-string $resourceClass */
    private function publishTranslations(string $resourceClass, string $modelClass): void
    {
        $translationClass = method_exists($modelClass, 'translationModelClass')
            ? $modelClass::translationModelClass()
            : $modelClass.'Translation';

        if (! class_exists($translationClass)) {
            return;
        }

        /** @var Collection<int, Model&Publishable> $records */
        $records = $translationClass::query()
            ->where('status', PublicationStatus::Scheduled->value)
            ->where('publish_at', '<=', now())
            ->get();

        if ($records->isEmpty()) {
            return;
        }

        $records->each(fn (Publishable $record) => $record->publish());

        $this->info("Published {$records->count()} {$resourceClass::getLabel()} translation(s).");
    }

    /** @param class-string $resourceClass */
    private function publishRecords(string $resourceClass, string $modelClass): void
    {
        /** @var Collection<int, Model&Publishable> $records */
        $records = $modelClass::query()
            ->where('status', PublicationStatus::Scheduled->value)
            ->where('publish_at', '<=', now())
            ->get();

        if ($records->isEmpty()) {
            return;
        }

        $records->each(fn (Publishable $record) => $record->publish());

        $this->info("Published {$records->count()} {$resourceClass::getLabel()} record(s).");
    }
}
