<?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\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasOne;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;

/**
 * @property int         $id
 * @property string      $type        direct|group
 * @property string|null $title
 * @property int         $created_by
 * @property \Carbon\Carbon|null $last_message_at
 * @property \Carbon\Carbon $created_at
 * @property \Carbon\Carbon $updated_at
 */
class Conversation extends Model
{
    use HasFactory;

    protected $fillable = [
        'uuid',
        'type',
        'title',
        'created_by',
        'last_message_id',
        'last_message_at',
        'is_active',
    ];

    protected $casts = [
        'last_message_at' => 'datetime',
        'is_active' => 'boolean',
    ];

    // ── Relationships ────────────────────────────────────────────────────────

    public function creator(): BelongsTo
    {
        return $this->belongsTo(User::class, 'created_by');
    }

    public function participants(): BelongsToMany
    {
        return $this->belongsToMany(User::class, 'conversation_participants')
            ->withPivot(['role', 'last_read_at', 'is_muted', 'is_archived', 'is_pinned', 'pinned_at', 'joined_at', 'left_at'])
            ->wherePivotNull('left_at');
    }

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

    public function messages(): HasMany
    {
        return $this->hasMany(Message::class)->orderBy('created_at');
    }

    public function latestMessage(): HasOne
    {
        return $this->hasOne(Message::class)->whereNull('deleted_at')->latestOfMany();
    }

    // ── Helpers ─────────────────────────────────────────────────────────────

    public function isDirect(): bool
    {
        return $this->type === 'direct';
    }

    public function isGroup(): bool
    {
        return $this->type === 'group';
    }

    /**
     * Find an existing direct conversation between exactly two users, or null.
     */
    public static function findDirect(int $userA, int $userB): ?self
    {
        return self::query()
            ->where('type', 'direct')
            ->where('is_active', true)
            ->whereHas('allParticipants', fn ($q) => $q->where('user_id', $userA)->whereNull('left_at'))
            ->whereHas('allParticipants', fn ($q) => $q->where('user_id', $userB)->whereNull('left_at'))
            ->whereRaw(
                '(select count(*) from conversation_participants'
                .' where conversation_participants.conversation_id = conversations.id'
                .' and left_at is null) = 2'
            )
            ->first();
    }

    /**
     * Compute unread count for a given participant.
     */
    public function unreadCountFor(int $userId): int
    {
        $participant = $this->allParticipants()
            ->where('user_id', $userId)
            ->first();

        if (! $participant) {
            return 0;
        }

        $query = $this->messages()
            ->whereNull('deleted_at')
            ->where('sender_id', '!=', $userId);

        if ($participant->last_read_message_id) {
            $query->where('id', '>', $participant->last_read_message_id);
            return $query->count();
        }

        if ($participant->last_read_at) {
            $query->where('created_at', '>', $participant->last_read_at);
        }

        return $query->count();
    }
}
