<?php

namespace App\Domain\Communication\Models;

use App\Domain\Communication\Enums\MessageStatus;
use App\Domain\Communication\Enums\NotificationChannel;
use App\Support\Concerns\HasUuid;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\MorphTo;
use RuntimeException;

/**
 * One outbound message, logged whatever happened to it (§56).
 *
 * The body is a snapshot: editing a template later must not change what a
 * recipient was actually told.
 */
class NotificationMessage extends Model
{
    use HasUuid;

    /** Only delivery outcome moves after a message is written. */
    private const MUTABLE = [
        'status', 'sent_at', 'read_at', 'failure_reason', 'attempts', 'updated_at',
    ];

    protected $guarded = ['id', 'uuid'];

    protected function casts(): array
    {
        return [
            'channel' => NotificationChannel::class,
            'status' => MessageStatus::class,
            'payload' => 'array',
            'queued_at' => 'datetime',
            'sent_at' => 'datetime',
            'read_at' => 'datetime',
            'attempts' => 'integer',
        ];
    }

    protected static function booted(): void
    {
        static::updating(function (self $message) {
            $touched = array_diff(array_keys($message->getDirty()), self::MUTABLE);

            if ($touched !== []) {
                throw new RuntimeException('A sent message is a record of what was said; it cannot be rewritten.');
            }
        });

        static::deleting(fn () => throw new RuntimeException('Communication history cannot be deleted.'));
    }

    public function recipient(): MorphTo
    {
        return $this->morphTo();
    }

    public function subject(): MorphTo
    {
        return $this->morphTo();
    }

    public function scopeUnread(Builder $query): Builder
    {
        return $query->whereNull('read_at')->where('channel', NotificationChannel::InApp->value);
    }

    public function scopeForRecipient(Builder $query, Model $recipient): Builder
    {
        return $query->where('recipient_type', $recipient->getMorphClass())
            ->where('recipient_id', $recipient->getKey());
    }
}
