<?php

namespace App\Services\Messaging;

use App\Models\Conversation;
use App\Models\ConversationParticipant;
use App\Models\Message;
use App\Models\User;
use Illuminate\Database\Eloquent\Builder;

class UnreadCounterService
{
    public function applyUnreadCountSelect(Builder $query, User|int $user, string $participantAlias = 'cp_me'): Builder
    {
        $userId = $user instanceof User ? (int) $user->id : (int) $user;

        return $query->addSelect([
            'unread_count' => Message::query()
                ->selectRaw('count(*)')
                ->whereColumn('messages.conversation_id', 'conversations.id')
                ->where('messages.sender_id', '!=', $userId)
                ->whereNull('messages.deleted_at')
                ->where(function ($nested) use ($participantAlias) {
                    $nested->where(function ($group) use ($participantAlias) {
                        $group->whereNull($participantAlias . '.last_read_message_id')
                            ->whereNull($participantAlias . '.last_read_at');
                    })->orWhereColumn('messages.id', '>', $participantAlias . '.last_read_message_id')
                        ->orWhereColumn('messages.created_at', '>', $participantAlias . '.last_read_at');
                }),
        ]);
    }

    public function unreadCountForConversation(Conversation $conversation, User|int $user): int
    {
        $userId = $user instanceof User ? (int) $user->id : (int) $user;

        $participant = ConversationParticipant::query()
            ->where('conversation_id', $conversation->id)
            ->where('user_id', $userId)
            ->whereNull('left_at')
            ->first();

        if (! $participant) {
            return 0;
        }

        return $this->unreadCountForParticipant($participant);
    }

    public function unreadCountForParticipant(ConversationParticipant $participant): int
    {
        $query = Message::query()
            ->where('conversation_id', $participant->conversation_id)
            ->where('sender_id', '!=', $participant->user_id)
            ->whereNull('deleted_at');

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

        return (int) $query->count();
    }

    public function totalUnreadForUser(User|int $user): int
    {
        $userId = $user instanceof User ? (int) $user->id : (int) $user;

        return (int) Conversation::query()
            ->select('conversations.id')
            ->join('conversation_participants as cp_me', function ($join) use ($userId) {
                $join->on('cp_me.conversation_id', '=', 'conversations.id')
                    ->where('cp_me.user_id', '=', $userId)
                    ->whereNull('cp_me.left_at');
            })
            ->where('conversations.is_active', true)
            ->get()
            ->sum(fn (Conversation $conversation) => $this->unreadCountForConversation($conversation, $userId));
    }
}
