using Ikar.Server.Data.Entities;
using Ikar.Server.Infrastructure.Bots;
using Ikar.Shared;
using Microsoft.EntityFrameworkCore;

namespace Ikar.Server.Tests;

public sealed class BotUpdateServiceTests
{
    [Fact]
    public async Task EnqueueIncomingMessageAsync_CreatesUpdateForGroupBotMember()
    {
        await using var database = new SqliteTestDatabase();
        await using var dbContext = await database.CreateContextAsync();
        var owner = CreateUser("owner");
        var botUser = CreateUser("groupbot", isBot: true);
        var bot = CreateBot(owner, botUser);
        var group = CreateChat(ChatType.Group, owner, botUser, botCanPost: false);
        var message = CreateMessage(group, owner, "hello group bot");
        dbContext.AddRange(owner, botUser, bot, group, message);
        await dbContext.SaveChangesAsync();

        var service = new BotUpdateService(dbContext);
        await service.EnqueueIncomingMessageAsync(message.Id, CancellationToken.None);

        var update = await dbContext.BotUpdates.SingleAsync();
        Assert.Equal(bot.Id, update.BotId);
        Assert.Equal(group.Id, update.ChatId);
        Assert.Equal(message.Id, update.MessageId);
    }

    [Fact]
    public async Task EnqueueIncomingMessageAsync_CreatesUpdateForChannelAdminBotOnly()
    {
        await using var database = new SqliteTestDatabase();
        await using var dbContext = await database.CreateContextAsync();
        var owner = CreateUser("owner");
        var adminBotUser = CreateUser("adminbot", isBot: true);
        var subscriberBotUser = CreateUser("subscriberbot", isBot: true);
        var adminBot = CreateBot(owner, adminBotUser);
        var subscriberBot = CreateBot(owner, subscriberBotUser);
        var channel = CreateChat(ChatType.Channel, owner, adminBotUser, botCanPost: true);
        channel.Members.Add(new ChatMember
        {
            ChatId = channel.Id,
            Chat = channel,
            UserId = subscriberBotUser.Id,
            User = subscriberBotUser,
            Role = ChatMemberRole.Member,
            CanPostMessages = false
        });
        var message = CreateMessage(channel, owner, "channel post");
        dbContext.AddRange(owner, adminBotUser, subscriberBotUser, adminBot, subscriberBot, channel, message);
        await dbContext.SaveChangesAsync();

        var service = new BotUpdateService(dbContext);
        await service.EnqueueIncomingMessageAsync(message.Id, CancellationToken.None);

        var update = await dbContext.BotUpdates.SingleAsync();
        Assert.Equal(adminBot.Id, update.BotId);
        Assert.DoesNotContain(dbContext.BotUpdates, x => x.BotId == subscriberBot.Id);
    }

    private static Bot CreateBot(User owner, User botUser) =>
        new()
        {
            Id = Guid.NewGuid(),
            UserId = botUser.Id,
            User = botUser,
            OwnerUserId = owner.Id,
            OwnerUser = owner,
            TokenHash = $"token-{botUser.Username}",
            IsEnabled = true
        };

    private static User CreateUser(string username, bool isBot = false) =>
        new()
        {
            Id = Guid.NewGuid(),
            Username = username,
            NormalizedUsername = username.ToUpperInvariant(),
            DisplayName = username,
            PasswordHash = "test",
            IsBot = isBot
        };

    private static Chat CreateChat(ChatType type, User owner, User botUser, bool botCanPost)
    {
        var chat = new Chat
        {
            Id = Guid.NewGuid(),
            Type = type,
            Title = type == ChatType.Channel ? "Channel" : "Group",
            CreatedById = owner.Id,
            CreatedBy = owner,
            CreatedAt = new DateTimeOffset(2026, 6, 1, 12, 0, 0, TimeSpan.Zero)
        };
        chat.Members.Add(new ChatMember
        {
            ChatId = chat.Id,
            Chat = chat,
            UserId = owner.Id,
            User = owner,
            IsOwner = true,
            Role = ChatMemberRole.Owner,
            CanPostMessages = true,
            CanDeleteMessages = true,
            CanInviteUsers = true,
            CanPinMessages = true
        });
        chat.Members.Add(new ChatMember
        {
            ChatId = chat.Id,
            Chat = chat,
            UserId = botUser.Id,
            User = botUser,
            Role = botCanPost ? ChatMemberRole.Admin : ChatMemberRole.Member,
            CanPostMessages = botCanPost,
            CanDeleteMessages = botCanPost,
            CanInviteUsers = botCanPost,
            CanPinMessages = botCanPost
        });
        return chat;
    }

    private static Message CreateMessage(Chat chat, User sender, string text)
    {
        var message = new Message
        {
            Id = Guid.NewGuid(),
            ChatId = chat.Id,
            Chat = chat,
            SenderId = sender.Id,
            Sender = sender,
            Text = text,
            SentAt = new DateTimeOffset(2026, 6, 1, 12, 5, 0, TimeSpan.Zero)
        };
        chat.Messages.Add(message);
        return message;
    }
}
