<?php

namespace App\Models;

use App\Enums\NotificationSeverityEnum;
use App\Enums\NotificationTypeEnum;
use Database\Factories\NotificationFactory;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\MorphTo;
use Illuminate\Support\Carbon;

/**
 * @property int $id
 * @property NotificationTypeEnum $type
 * @property NotificationSeverityEnum $severity
 * @property string $title
 * @property string $message
 * @property array<string, mixed>|null $data
 * @property string|null $notifiable_type
 * @property int|null $notifiable_id
 * @property Carbon|null $read_at
 * @property Carbon $created_at
 * @property Carbon $updated_at
 */
class Notification extends Model
{
    /** @use HasFactory<NotificationFactory> */
    use HasFactory;

    protected $fillable = [
        'type',
        'severity',
        'title',
        'message',
        'data',
        'notifiable_type',
        'notifiable_id',
        'read_at',
    ];

    protected $casts = [
        'type' => NotificationTypeEnum::class,
        'severity' => NotificationSeverityEnum::class,
        'data' => 'array',
        'read_at' => 'datetime',
        'created_at' => 'datetime',
        'updated_at' => 'datetime',
    ];

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

    public function isRead(): bool
    {
        return $this->read_at !== null;
    }

    public function markAsRead(): void
    {
        $this->update(['read_at' => now()]);
    }

    /**
     * @param  Builder<Notification>  $query
     * @return Builder<Notification>
     */
    public function scopeUnread(Builder $query): Builder
    {
        return $query->whereNull('read_at');
    }

    /**
     * @param  Builder<Notification>  $query
     * @return Builder<Notification>
     */
    public function scopeRecent(Builder $query): Builder
    {
        return $query->latest()->limit(50);
    }

    public static function markAllAsRead(): void
    {
        static::unread()->update(['read_at' => now()]);
    }
}
