<?php

declare(strict_types=1);

namespace App\Models;

use App\Enums\FraudFlagSeverity;
use App\Enums\FraudFlagStatus;
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\MorphTo;

/**
 * An internal risk signal raised against a user, listing, offer or order.
 *
 * Section 28 requires that fraud signals are never exposed to normal users.
 * There is deliberately no API resource for this model outside the admin
 * namespace, and no relation from it is eager-loaded on a public query.
 *
 * @method static Builder<static> unresolved()
 */
class FraudFlag extends Model
{
    use HasFactory;

    /** @var list<string> */
    protected $fillable = [
        'flaggable_type',
        'flaggable_id',
        'type',
        'severity',
        'score',
        'detected_by',
        'reason',
        'signals',
        'auto_actioned',
        'auto_action',
    ];

    /**
     * Mirrors the column defaults in the migration.
     *
     * @var array<string, mixed>
     */
    protected $attributes = [
        'severity' => 'low',
        'status' => 'open',
        'score' => 0,
        'detected_by' => 'system',
        'auto_actioned' => false,
    ];

    /** @return array<string, string> */
    protected function casts(): array
    {
        return [
            'severity' => FraudFlagSeverity::class,
            'status' => FraudFlagStatus::class,
            'signals' => 'array',
            'auto_actioned' => 'boolean',
            'reviewed_at' => 'datetime',
        ];
    }

    /** @return MorphTo<Model, $this> */
    public function flaggable(): MorphTo
    {
        return $this->morphTo();
    }

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

    /** @param  Builder<static>  $query */
    public function scopeUnresolved(Builder $query): void
    {
        $query->whereIn('status', [FraudFlagStatus::Open->value, FraudFlagStatus::Reviewing->value]);
    }

    /** @param  Builder<static>  $query */
    public function scopeOfSeverityAtLeast(Builder $query, FraudFlagSeverity $severity): void
    {
        $order = [
            FraudFlagSeverity::Low->value,
            FraudFlagSeverity::Medium->value,
            FraudFlagSeverity::High->value,
            FraudFlagSeverity::Critical->value,
        ];

        $index = array_search($severity->value, $order, true);

        $query->whereIn('severity', array_slice($order, (int) $index));
    }
}
