<?php

declare(strict_types=1);

namespace App\Models;

use App\Facades\Search;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;

/**
 * App\Models\ReleaseFile.
 *
 * @property int $releases_id FK to releases.id
 * @property string $name
 * @property int $size
 * @property \Carbon\Carbon|null $created_at
 * @property \Carbon\Carbon|null $updated_at
 * @property bool $passworded
 * @property-read Release $release
 *
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\ReleaseFile whereCreatedAt($value)
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\ReleaseFile whereName($value)
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\ReleaseFile wherePassworded($value)
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\ReleaseFile whereReleasesId($value)
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\ReleaseFile whereSize($value)
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\ReleaseFile whereUpdatedAt($value)
 *
 * @mixin \Eloquent
 *
 * @property string $crc32
 *
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\ReleaseFile newModelQuery()
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\ReleaseFile newQuery()
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\ReleaseFile query()
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Models\ReleaseFile whereCrc32($value)
 */
class ReleaseFile extends Model
{
    protected $dateFormat = false;

    /**
     * @var array<string>
     */
    protected $guarded = [];

    /**
     * @var string
     */
    protected $primaryKey = 'releases_id';

    /**
     * @return BelongsTo<mixed>
     */
    public function release(): \Illuminate\Database\Eloquent\Relations\BelongsTo // @phpstan-ignore class.notFound, missingType.generics, return.phpDocType
    {
        return $this->belongsTo(Release::class, 'releases_id');
    }

    /**
     * Scope to filter release files that look like NFO files.
     *
     * @param  Builder<self>  $query
     * @return Builder<self>
     */
    public function scopeNfoFiles(Builder $query): Builder
    {
        return $query->where(function (Builder $q) {
            $q->where('name', 'like', '%.nfo')
                ->orWhere('name', 'like', '%.diz')
                ->orWhere('name', 'like', '%.inf')
                ->orWhere('name', 'like', '%file\_id.diz')
                ->orWhere('name', 'like', '%info.txt');
        });
    }

    /**
     * Scope to filter NFO files that have non-zero size (likely contain actual content).
     *
     * @param  Builder<self>  $query
     * @return Builder<self>
     */
    public function scopeNfoFilesWithContent(Builder $query): Builder
    {
        return $query->nfoFiles()->where('size', '>', 0);
    }

    /**
     * Get releasefiles row by id.
     */
    public static function getReleaseFiles(mixed $id): mixed
    {
        return self::query()->where('releases_id', $id)->orderBy('name')->get();
    }

    public static function getByGuid(mixed $guid): mixed
    {
        return self::query()
            ->join('releases', 'releases.id', '=', 'release_files.releases_id')
            ->where('releases.guid', $guid)
            ->orderBy('release_files.name')->get();
    }

    /**
     * Add new files for a release ID.
     *
     *
     *
     * @throws \Exception
     */
    public static function addReleaseFiles(mixed $id, mixed $name, mixed $size, mixed $createdTime, mixed $hasPassword, string $hash = '', string $crc = ''): int
    {
        // Check if we already have this data in table
        $duplicateCheck = self::query()->where('releases_id', $id)->where('name', $name)->first();

        // Check if the release exists in releases table to prevent foreign key error
        $releaseCheck = Release::query()->where('id', $id)->first();

        if (is_int($createdTime)) {
            if ($createdTime === 0) {
                $adjustedCreatedTime = now()->format('Y-m-d H:i:s');
            } else {
                $adjustedCreatedTime = Carbon::createFromTimestamp($createdTime, date_default_timezone_get())->format('Y-m-d H:i:s');
            }
        } else {
            $adjustedCreatedTime = $createdTime;
        }

        if ($duplicateCheck === null && $releaseCheck !== null) {
            try {
                $insert = self::insertOrIgnore([
                    'releases_id' => $id,
                    'name' => $name,
                    'size' => $size,
                    'created_at' => $adjustedCreatedTime,
                    'updated_at' => now()->timestamp,
                    'passworded' => $hasPassword,
                    'crc32' => $crc,
                ]);
            } catch (\PDOException $e) {
                Log::alert($e->getMessage());
            }

            if (\strlen($hash) === 32) {
                ParHash::insertOrIgnore(['releases_id' => $id, 'hash' => $hash]);
            }
            DB::afterCommit(function () use ($id): void {
                Search::updateRelease($id);
            });
        }

        return $insert ?? 0;
    }
}
