<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Carbon;

class ChatMessage extends Model
{
    use HasFactory, SoftDeletes;

    protected $table = 'chat_messages';
    protected $primaryKey = 'message_id';
    public $incrementing = true;

    /**
     * Disable Laravel's default created_at / updated_at columns.
     * We manage sent_at ourselves.
     */
    public $timestamps = false;

    protected $fillable = [
        'chat_id',
        'sender_id',
        'message_type',
        'message',
        'file_id',
        'call_type',
        'call_status',
        'is_read',
        'is_deleted',
        'sent_at',
        'read_at',
    ];

    protected $casts = [
        'is_read'    => 'boolean',
        'is_deleted' => 'boolean',
        'sent_at'    => 'datetime',
        'read_at'    => 'datetime',
    ];

    // -------------------------------------------------------------------------
    // FIX #1 — removed $appends = ['sender'].
    // Appending an attribute named 'sender' that delegates to the 'sender'
    // relationship causes infinite recursion in many Laravel versions.
    // Load the relationship explicitly in queries instead: ->with('senderUser')
    // -------------------------------------------------------------------------

    // -------------------------------------------------------------------------
    // FIX #2 — bootSaving() is not a valid Laravel hook name and never fires.
    // The correct hook is static::boot() + static::saving(...) inside it,
    // OR the modern approach: booted() with the observer registration.
    // -------------------------------------------------------------------------
    protected static function booted(): void
    {
        static::saving(function (self $model): void {
            if (is_null($model->sent_at)) {
                $model->sent_at = now();
            }
            if (is_null($model->is_read)) {
                $model->is_read = false;
            }
        });
    }

    // -------------------------------------------------------------------------
    // Relationships
    // -------------------------------------------------------------------------

    public function chat(): BelongsTo
    {
        return $this->belongsTo(ChatRoom::class, 'chat_id', 'chat_id');
    }

    /**
     * Renamed to senderUser to avoid the name collision with the old
     * getSenderAttribute() accessor that caused infinite recursion (FIX #1).
     */
    public function senderUser(): BelongsTo
    {
        return $this->belongsTo(User::class, 'sender_id');
    }

    public function file(): BelongsTo
    {
        return $this->belongsTo(UploadedChatFile::class, 'file_id');
    }

    // -------------------------------------------------------------------------
    // Scopes
    // -------------------------------------------------------------------------

    public function scopeForChat($query, int $chatId)
    {
        return $query->where('chat_id', $chatId);
    }

    public function scopeUnread($query, int $userId)
    {
        return $query->where('sender_id', '!=', $userId)
                     ->where('is_read', false);
    }

    /**
     * FIX #4 — default sort is ASC so messages appear in chronological order.
     * Pass 'desc' explicitly if you need reverse order.
     */
    public function scopeRecent($query, int $limit = 50, string $direction = 'asc')
    {
        return $query->orderBy('sent_at', $direction)->limit($limit);
    }

    public function scopeSince($query, $timestamp)
    {
        return $query->where('sent_at', '>', Carbon::parse($timestamp));
    }

    // -------------------------------------------------------------------------
    // Business logic
    // -------------------------------------------------------------------------

    /**
     * Mark this message as read by $userId.
     * Only marks if the message was sent by someone else and not yet read.
     */
    public function markAsRead(int $userId): void
    {
        if (! $this->is_read && $this->sender_id !== $userId) {
            $this->update([
                'is_read'  => true,
                'read_at'  => now(),
            ]);
        }
    }
}