<?php

namespace App\Models;

use App\Helpers\EntryHelpers;
use App\Models\Scopes\NsfwScope;
use App\Traits\HasGallery;
use App\Traits\HasXenforoUserId;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\SoftDeletes;
use League\CommonMark\GithubFlavoredMarkdownConverter;
use Monolog\Level;
use Spatie\Activitylog\Models\Concerns\LogsActivity;
use Spatie\Activitylog\Support\LogOptions;

/**
 * @property int $id
 * @property string $type
 * @property string|null $title
 * @property string|null $slug
 * @property string|null $description
 * @property string|null $main_image
 * @property string $state
 * @property string|null $staff_comment
 * @property \Illuminate\Support\Carbon|null $rejected_at
 * @property bool $featured
 * @property \Illuminate\Support\Carbon|null $featured_at
 * @property int|null $game_id
 * @property int|null $platform_id
 * @property int|null $status_id
 * @property string|null $version
 * @property \Illuminate\Support\Carbon|null $release_date
 * @property string|null $staff_credits
 * @property string|null $relevant_link
 * @property string|null $youtube_link
 * @property int $user_id
 * @property int|null $comments_thread_id
 * @property \Illuminate\Support\Carbon|null $created_at
 * @property \Illuminate\Support\Carbon|null $updated_at
 * @property string|null $complete_title
 * @property \Illuminate\Support\Carbon|null $deleted_at
 * @property int|null $level_id
 * @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Author> $authors
 * @property-read int|null $authors_count
 * @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Category> $categories
 * @property-read int|null $categories_count
 * @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\EntryFile> $files
 * @property-read int|null $files_count
 * @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Gallery> $gallery
 * @property-read int|null $gallery_count
 * @property-read \App\Models\Game|null $game
 * @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\EntryHash> $hashes
 * @property-read int|null $hashes_count
 * @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Language> $languages
 * @property-read int|null $languages_count
 * @property-read \App\Models\Level|null $level
 * @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Modification> $modifications
 * @property-read int|null $modifications_count
 * @property-read \App\Models\Platform|null $platform
 * @property-read \App\Models\Status|null $status
 * @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\System> $systems
 * @property-read int|null $systems_count
 * @method static Builder<static>|Entry inQueue(int $daysRejected = 7)
 * @method static Builder<static>|Entry newModelQuery()
 * @method static Builder<static>|Entry newQuery()
 * @method static Builder<static>|Entry onlyTrashed()
 * @method static Builder<static>|Entry published()
 * @method static Builder<static>|Entry query()
 * @method static Builder<static>|Entry whereCommentsThreadId($value)
 * @method static Builder<static>|Entry whereCompleteTitle($value)
 * @method static Builder<static>|Entry whereCreatedAt($value)
 * @method static Builder<static>|Entry whereDeletedAt($value)
 * @method static Builder<static>|Entry whereDescription($value)
 * @method static Builder<static>|Entry whereFeatured($value)
 * @method static Builder<static>|Entry whereFeaturedAt($value)
 * @method static Builder<static>|Entry whereGameId($value)
 * @method static Builder<static>|Entry whereId($value)
 * @method static Builder<static>|Entry whereLevelId($value)
 * @method static Builder<static>|Entry whereMainImage($value)
 * @method static Builder<static>|Entry wherePlatformId($value)
 * @method static Builder<static>|Entry whereRejectedAt($value)
 * @method static Builder<static>|Entry whereReleaseDate($value)
 * @method static Builder<static>|Entry whereRelevantLink($value)
 * @method static Builder<static>|Entry whereSlug($value)
 * @method static Builder<static>|Entry whereStaffComment($value)
 * @method static Builder<static>|Entry whereStaffCredits($value)
 * @method static Builder<static>|Entry whereState($value)
 * @method static Builder<static>|Entry whereStatusId($value)
 * @method static Builder<static>|Entry whereTitle($value)
 * @method static Builder<static>|Entry whereType($value)
 * @method static Builder<static>|Entry whereUpdatedAt($value)
 * @method static Builder<static>|Entry whereUserId($value)
 * @method static Builder<static>|Entry whereVersion($value)
 * @method static Builder<static>|Entry whereYoutubeLink($value)
 * @method static Builder<static>|Entry withTrashed(bool $withTrashed = true)
 * @method static Builder<static>|Entry withoutTrashed()
 * @property-read \Illuminate\Database\Eloquent\Collection<int, \Spatie\Activitylog\Models\Activity> $activitiesAsSubject
 * @property-read int|null $activities_as_subject_count
 * @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\EntryReview> $reviews
 * @property-read int|null $reviews_count
 * @property-read float $average_rating
 * @property-read int $reviews_count_cached
 * @property-read string $description_html
 * @mixin \Eloquent
 */
class Entry extends Model
{

    use SoftDeletes, HasGallery, LogsActivity, HasXenforoUserId;

    /**
     * @var string[]
     */
    protected $fillable = [
        'type',
        'title',
        'slug',
        'description',
        'main_image',
        'state',
        'featured',
        'featured_at',
        'game_id',
        'platform_id',
        'status_id',
        'version',
        'release_date',
        'staff_credits',
        'relevant_link',
        'youtube_link',
        'user_id',
        'complete_title',
        'comments_thread_id',
        'staff_comment',
        'rejected_at',
        'level_id',
        'created_at',
        'nsfw'
    ];

    /**
     * @var string[]
     */
    protected $casts = [
        'featured' => 'boolean',
        'release_date' => 'date',
        'rejected_at' => 'datetime',
        'featured_at' => 'datetime',
    ];

    protected static function booted(): void {

        static::addGlobalScope(new NsfwScope);

        static::saving( function( $entry ) {
            if( $entry->isDirty('version') ) {
                $entry->created_at = now();
            }
        });

    }


    public function scopePublished( Builder $query ): Builder {
        return $query->where( 'state', 'published' );
    }

    public function scopeInQueue( Builder $query, int $daysRejected = 7 ): Builder {
        return $query->withTrashed()->where(function($q) use($daysRejected) {
            $q->where('state', 'pending')->whereNull('deleted_at');
        })->orWhere(function($q) use($daysRejected) {
            $q->where('state', 'rejected')->whereNotNull('rejected_at')->where('rejected_at', '>=', now()->subDays($daysRejected) );
        });
    }

    /**
     * Return game link.
     * @return BelongsTo
     */
    public function game(): BelongsTo {
        return $this->belongsTo(Game::class);
    }

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

    public function getRealPlatform(): ?Platform {
        return $this->game?->platform ?? $this->platform;
    }

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

    public function level(): BelongsTo {
        return $this->belongsTo(\App\Models\Level::class);
    }

    public function authors(): BelongsToMany {
        return $this->belongsToMany(Author::class, 'entry_authors');
    }

    public function languages(): BelongsToMany {
        return $this->belongsToMany(Language::class, 'entry_languages');
    }

    public function modifications(): BelongsToMany {
        return $this->belongsToMany( Modification::class, 'entry_modifications');
    }

    public function categories(): BelongsToMany {
        return $this->belongsToMany(Category::class, 'entry_categories');
    }

    public function systems(): BelongsToMany {
        return $this->belongsToMany(System::class, 'entry_systems');
    }

    public function files(): HasMany {
        return $this->hasMany(EntryFile::class)->orderBy('filename');
    }

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

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

    public function getAverageRatingAttribute(): float
    {
        return round( $this->reviews->avg('rating') ?? 0, 1 );
    }

    public function getReviewsCountCachedAttribute(): int
    {
        return $this->reviews->count();
    }

    public function getDescriptionHtmlAttribute(): string
    {
        $converter = new GithubFlavoredMarkdownConverter([
            'html_input'         => 'strip',
            'allow_unsafe_links' => false,
        ]);

        return $converter->convert($this->description)->getContent();
    }

    public function getTotalDownloadsAttribute(): int
    {
        return $this->files->sum('download_count');
    }

    public function parseStaffCredits(): ?array {
        return json_decode( $this->staff_credits ?? "", true );
    }

    public function getYoutubeVideoId(): ?string {
        if( !$this->youtube_link )
            return null;

        return EntryHelpers::getYoutubeVideoId( $this->youtube_link );
    }

    public function getActivitylogOptions(): LogOptions
    {
        return LogOptions::defaults()
            ->useLogName('entry')
            ->logAll()
            ->logOnlyDirty()
            ->dontLogEmptyChanges()
            ->setDescriptionForEvent(fn(string $eventName) => "Entry {$eventName}");
    }

}
