<?php

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\SoftDeletes;
use Illuminate\Support\HtmlString;
use Illuminate\Support\Str;

class ContentPage extends Model
{
    use HasFactory, SoftDeletes;

    public const STATUS_DRAFT = 'draft';

    public const STATUS_PUBLISHED = 'published';

    protected $fillable = [
        'created_by_id',
        'updated_by_id',
        'title',
        'slug',
        'excerpt',
        'content',
        'status',
        'show_in_footer',
        'footer_label',
        'footer_sort',
        'meta_title',
        'meta_description',
        'published_at',
    ];

    /**
     * @return BelongsTo<User, $this>
     */
    public function createdBy(): BelongsTo
    {
        return $this->belongsTo(User::class, 'created_by_id');
    }

    /**
     * @return BelongsTo<User, $this>
     */
    public function updatedBy(): BelongsTo
    {
        return $this->belongsTo(User::class, 'updated_by_id');
    }

    /**
     * @param  Builder<ContentPage>  $query
     * @return Builder<ContentPage>
     */
    public function scopePublished(Builder $query): Builder
    {
        return $query
            ->where('status', self::STATUS_PUBLISHED)
            ->whereNotNull('published_at')
            ->where('published_at', '<=', now());
    }

    public function publicUrl(): string
    {
        return route('content-pages.show', $this->slug);
    }

    public function publicPath(): string
    {
        return '/pages/'.$this->slug;
    }

    public function displayFooterLabel(): string
    {
        return $this->footer_label ?: $this->title;
    }

    public function renderedContent(): HtmlString
    {
        $paragraphs = collect(preg_split("/\n{2,}/", (string) $this->content) ?: [])
            ->map(fn (string $paragraph): string => trim($paragraph))
            ->filter()
            ->map(function (string $paragraph): string {
                if (Str::startsWith($paragraph, '### ')) {
                    return '<h3>'.e(Str::after($paragraph, '### ')).'</h3>';
                }

                if (Str::startsWith($paragraph, '## ')) {
                    return '<h2>'.e(Str::after($paragraph, '## ')).'</h2>';
                }

                if (Str::startsWith($paragraph, '# ')) {
                    return '<h2>'.e(Str::after($paragraph, '# ')).'</h2>';
                }

                return '<p>'.nl2br(e($paragraph)).'</p>';
            })
            ->implode("\n");

        return new HtmlString($paragraphs);
    }

    protected static function booted(): void
    {
        static::saving(function (ContentPage $page): void {
            if (! filled($page->slug)) {
                $page->slug = Str::slug($page->title);
            }

            $page->slug = Str::slug($page->slug);

            if ($page->status === self::STATUS_PUBLISHED && $page->published_at === null) {
                $page->published_at = now();
            }
        });
    }

    /**
     * Get the attributes that should be cast.
     *
     * @return array<string, string>
     */
    protected function casts(): array
    {
        return [
            'show_in_footer' => 'boolean',
            'footer_sort' => 'integer',
            'published_at' => 'datetime',
        ];
    }
}
