<?php

namespace App\Models;

use App\Enums\KeywordDevice;
use App\Enums\SearchEngine;
use App\Enums\SerpCheckStatus;
use Illuminate\Database\Eloquent\Concerns\HasUlids;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use LogicException;

class SerpCheck extends Model
{
    use HasFactory,HasUlids;

    protected $guarded = ['id', 'keyword_id', 'ulid'];

    protected function casts(): array
    {
        return ['status' => SerpCheckStatus::class, 'search_engine' => SearchEngine::class, 'device' => KeywordDevice::class, 'checked_at' => 'datetime', 'started_at' => 'datetime', 'completed_at' => 'datetime', 'failed_at' => 'datetime', 'provider_task_posted_at' => 'datetime', 'provider_last_polled_at' => 'datetime', 'provider_next_poll_at' => 'datetime', 'provider_cost' => 'decimal:6'];
    }

    public function uniqueIds(): array
    {
        return ['ulid'];
    }

    public function getRouteKeyName(): string
    {
        return 'ulid';
    }

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

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

    public function begin(): bool
    {
        if ($this->status !== SerpCheckStatus::Pending) {
            return false;
        }

        return $this->forceFill(['status' => SerpCheckStatus::Running, 'active_slot' => 'active', 'started_at' => now()])->save();
    }

    public function complete(array $data): bool
    {
        if ($this->status !== SerpCheckStatus::Running) {
            throw new LogicException('Invalid check transition.');
        }

        return $this->forceFill($data + ['status' => SerpCheckStatus::Completed, 'active_slot' => null, 'checked_at' => now(), 'completed_at' => now(), 'failed_at' => null, 'error_code' => null, 'error_message' => null])->save();
    }

    public function fail(string $code, string $message): bool
    {
        if (! in_array($this->status, [SerpCheckStatus::Pending, SerpCheckStatus::Running], true)) {
            return false;
        }

        return $this->forceFill(['status' => SerpCheckStatus::Failed, 'active_slot' => null, 'failed_at' => now(), 'error_code' => $code, 'error_message' => $message])->save();
    }
}
