using Ikar.Server.Data;
using Ikar.Server.Data.Entities;
using Microsoft.EntityFrameworkCore;

namespace Ikar.Server.Infrastructure.Bots;

public sealed class BotUpdateService(IkarDbContext dbContext)
{
    public async Task EnqueueIncomingMessageAsync(Guid messageId, CancellationToken cancellationToken = default)
    {
        var message = await dbContext.Messages
            .Include(x => x.Sender)
            .Include(x => x.Chat)
                .ThenInclude(x => x.Members)
                    .ThenInclude(x => x.User)
                        .ThenInclude(x => x.BotProfile)
            .SingleOrDefaultAsync(x => x.Id == messageId, cancellationToken);

        if (message is null ||
            message.Sender.IsBot ||
            message.Chat.Type != Ikar.Shared.ChatType.Direct ||
            message.Chat.Members.Count != 2)
        {
            return;
        }

        var botMember = message.Chat.Members
            .FirstOrDefault(member => member.User.IsBot && member.User.BotProfile is not null);
        if (botMember?.User.BotProfile is null || !botMember.User.BotProfile.IsEnabled)
        {
            return;
        }

        var updateExists = await dbContext.BotUpdates
            .AsNoTracking()
            .AnyAsync(
                x => x.BotId == botMember.User.BotProfile.Id &&
                     x.MessageId == message.Id,
                cancellationToken);
        if (updateExists)
        {
            return;
        }

        dbContext.BotUpdates.Add(new BotUpdate
        {
            BotId = botMember.User.BotProfile.Id,
            ChatId = message.ChatId,
            MessageId = message.Id,
            CreatedAt = message.SentAt
        });

        await dbContext.SaveChangesAsync(cancellationToken);
    }

    public async Task MarkMessagesReadByBotAsync(
        Guid botUserId,
        IReadOnlyCollection<Message> messages,
        CancellationToken cancellationToken = default)
    {
        var maxByChat = messages
            .GroupBy(message => message.ChatId)
            .Select(group => new
            {
                ChatId = group.Key,
                MaxSentAt = group.Max(message => message.SentAt)
            })
            .ToList();

        foreach (var item in maxByChat)
        {
            var membership = await dbContext.ChatMembers
                .SingleOrDefaultAsync(
                    x => x.ChatId == item.ChatId && x.UserId == botUserId,
                    cancellationToken);
            if (membership is null)
            {
                continue;
            }

            if (membership.LastDeliveredAt is null || membership.LastDeliveredAt < item.MaxSentAt)
            {
                membership.LastDeliveredAt = item.MaxSentAt;
            }

            if (membership.LastReadAt is null || membership.LastReadAt < item.MaxSentAt)
            {
                membership.LastReadAt = item.MaxSentAt;
            }
        }

        await dbContext.SaveChangesAsync(cancellationToken);
    }
}
