<?php

declare(strict_types=1);

namespace Builder\Core\Foundation\Concerns;

use Builder\Core\Foundation\Enums\PublicationStatus;
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Carbon;

/**
 * Adds publishing semantics (draft / scheduled / published) to an Eloquent
 * model. The host model is expected to have the `status` + `publish_at`
 * columns — call {@see HasPublishing::publishingColumns()} from your
 * migration to add them.
 *
 * @property PublicationStatus $status
 * @property Carbon|null $publish_at
 *
 * @phpstan-require-extends Model
 */
trait HasPublishing
{
    /**
     * Helper for migration files — adds the two publishing columns to a table.
     *
     * Usage in a migration:
     *   HasPublishing::publishingColumns($table);
     */
    public static function publishingColumns(Blueprint $table): void
    {
        $table->string('status')->default(PublicationStatus::Draft->value);
        $table->timestamp('publish_at')->nullable();
    }

    public static function bootHasPublishing(): void
    {
        static::saving(function (self $model): void {
            if ($model->status !== PublicationStatus::Scheduled) {
                $model->publish_at = null;
            }
        });
    }

    public function initializeHasPublishing(): void
    {
        $this->casts['status'] = PublicationStatus::class;
        $this->casts['publish_at'] = 'datetime';
        $this->attributes['status'] ??= PublicationStatus::Draft->value;
    }

    public function publish(): void
    {
        $this->status = PublicationStatus::Published;
        $this->publish_at = null;
        $this->save();
    }

    public function unpublish(): void
    {
        $this->status = PublicationStatus::Draft;
        $this->publish_at = null;
        $this->save();
    }

    public function schedulePublish(Carbon $at): void
    {
        $this->status = PublicationStatus::Scheduled;
        $this->publish_at = $at;
        $this->save();
    }

    public function isPublished(): bool
    {
        return $this->status === PublicationStatus::Published;
    }

    public function isDraft(): bool
    {
        return $this->status === PublicationStatus::Draft;
    }

    public function isScheduled(): bool
    {
        return $this->status === PublicationStatus::Scheduled;
    }

    /**
     * @param  EloquentBuilder<Model>  $query
     * @return EloquentBuilder<Model>
     */
    public function scopePublished(EloquentBuilder $query): EloquentBuilder
    {
        return $query->where('status', PublicationStatus::Published->value);
    }

    /**
     * @param  EloquentBuilder<Model>  $query
     * @return EloquentBuilder<Model>
     */
    public function scopeDraft(EloquentBuilder $query): EloquentBuilder
    {
        return $query->where('status', PublicationStatus::Draft->value);
    }

    /**
     * @param  EloquentBuilder<Model>  $query
     * @return EloquentBuilder<Model>
     */
    public function scopeScheduled(EloquentBuilder $query): EloquentBuilder
    {
        return $query->where('status', PublicationStatus::Scheduled->value);
    }
}
