using Knot.Contracts.Messaging.Application.Abstractions;
using Knot.Contracts.Messaging.Domain;
using MongoDB.Driver;

namespace Knot.Modules.Messaging.Infrastructure.Persistence;

public sealed class MessageReactionRepository : IMessageReactionRepository
{
    private readonly IMongoCollection<MessageReaction> _reactions;
    private readonly MediatR.IMediator _mediator;
    private readonly IMessageRepository _messageRepository;

    public MessageReactionRepository(IMongoDatabase mongoDatabase, MediatR.IMediator mediator, IMessageRepository messageRepository)
    {
        _reactions = mongoDatabase.GetCollection<MessageReaction>("message_reactions");
        _mediator = mediator;
        _messageRepository = messageRepository;

        // Ensure index for fast querying by message
        var indexKeysDefinition = Builders<MessageReaction>.IndexKeys.Ascending(r => r.MessageId);
        _reactions.Indexes.CreateOne(new CreateIndexModel<MessageReaction>(indexKeysDefinition));
    }

    public async Task AddAsync(MessageReaction reaction, CancellationToken cancellationToken)
    {
        var filter = Builders<MessageReaction>.Filter.And(
            Builders<MessageReaction>.Filter.Eq(r => r.MessageId, reaction.MessageId),
            Builders<MessageReaction>.Filter.Eq(r => r.UserId, reaction.UserId),
            Builders<MessageReaction>.Filter.Eq(r => r.Emoji, reaction.Emoji)
        );

        await _reactions.ReplaceOneAsync(filter, reaction, new ReplaceOptions { IsUpsert = true }, cancellationToken);

        var message = await _messageRepository.GetByIdAsync(reaction.MessageId, cancellationToken);
        if (message != null)
        {
            await _mediator.Publish(new MessageReactionAddedDomainEvent(reaction.MessageId, message.ChatId, reaction.UserId, reaction.Emoji), cancellationToken);
        }
    }

    public async Task RemoveAsync(Guid messageId, Guid userId, string emoji, CancellationToken cancellationToken)
    {
        var filter = Builders<MessageReaction>.Filter.And(
            Builders<MessageReaction>.Filter.Eq(r => r.MessageId, messageId),
            Builders<MessageReaction>.Filter.Eq(r => r.UserId, userId),
            Builders<MessageReaction>.Filter.Eq(r => r.Emoji, emoji)
        );

        await _reactions.DeleteOneAsync(filter, cancellationToken);

        var message = await _messageRepository.GetByIdAsync(messageId, cancellationToken);
        if (message != null)
        {
            await _mediator.Publish(new MessageReactionRemovedDomainEvent(messageId, message.ChatId, userId, emoji), cancellationToken);
        }
    }

    public async Task<List<MessageReaction>> GetReactionsForMessageAsync(Guid messageId, CancellationToken cancellationToken)
    {
        return await _reactions.Find(r => r.MessageId == messageId).ToListAsync(cancellationToken);
    }

    public async Task<List<MessageReaction>> GetReactionsForMessagesAsync(IEnumerable<Guid> messageIds, CancellationToken cancellationToken)
    {
        var filter = Builders<MessageReaction>.Filter.In(r => r.MessageId, messageIds);
        return await _reactions.Find(filter).ToListAsync(cancellationToken);
    }
}


