<?php

declare(strict_types=1);


namespace App\Models;

use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Spatie\MediaLibrary\HasMedia;
use Spatie\MediaLibrary\InteractsWithMedia;
use Spatie\MediaLibrary\MediaCollections\Models\Media;
use Spatie\Tags\HasTags;

class Post extends Model implements HasMedia
{
    use HasFactory;
    use InteractsWithMedia;
    use HasTags;

    protected $fillable = [
        'category_id',
        'user_id',
        'title',
        'slug',
        'excerpt',
        'content',
        'content_format',
        'keywords',
        'status',
        'is_sticky',
        'close_comment',
        'read_password',
        'views',
        'comment_count',
        'meta',
        'published_at',
    ];

    protected $casts = [
        'meta' => 'array',
        'is_sticky' => 'boolean',
        'close_comment' => 'boolean',
        'published_at' => 'datetime',
    ];

    public function category(): BelongsTo
    {
        return $this->belongsTo(Category::class);
    }

    public function author(): BelongsTo
    {
        return $this->belongsTo(User::class, 'user_id');
    }

    public function comments(): HasMany
    {
        return $this->hasMany(Comment::class);
    }

    public function scopePublished(Builder $query): Builder
    {
        return $query->where('status', 'published')
            ->whereNotNull('published_at')
            ->where('published_at', '<=', now());
    }

    public function scopeSearch(Builder $query, ?string $keyword): Builder
    {
        if (! $keyword) {
            return $query;
        }

        return $query->where(function (Builder $q) use ($keyword) {
            $q->where('title', 'like', "%{$keyword}%")
                ->orWhere('content', 'like', "%{$keyword}%")
                ->orWhere('excerpt', 'like', "%{$keyword}%")
                ->orWhere('keywords', 'like', "%{$keyword}%");
        });
    }

    public function registerMediaCollections(): void
    {
        $this->addMediaCollection('attachments')->useDisk(\App\Support\MediaDisk::name());
        $this->addMediaCollection('cover')->useDisk(\App\Support\MediaDisk::name())
            ->singleFile()
            ->registerMediaConversions(function () {
                $this->addMediaConversion('card')->width(1200)->height(630)->sharpen(1);
            });
    }

    public function registerMediaConversions(?Media $media = null): void
    {
        [$tw, $th] = array_pad(explode('x', strtolower((string) blog_setting('attachments_thumbs_size', '500x500'))), 2, '500');
        $this->addMediaConversion('thumb')
            ->width((int) $tw)
            ->height((int) $th)
            ->performOnCollections('attachments');
    }

    public function getUrlAttribute(): string
    {
        return route('posts.show', $this->slug ?? $this->id);
    }

    public function getExcerptOrFallbackAttribute(): string
    {
        if ($this->excerpt) {
            return $this->excerpt;
        }

        $text = strip_tags($this->content);
        // 付费块不进入摘要，避免付费内容泄漏到列表页/SEO meta
        $text = preg_replace('/\[paid\].*?\[\/paid\]/s', '', $text);
        $text = preg_replace('/\[[^\]]*\]/', '', $text);

        return mb_substr($text, 0, 200);
    }
}
