using Ikar.Server.Data.Entities;
using Ikar.Shared;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;

namespace Ikar.Server.Tests;

public sealed class BotsControllerTests
{
    [Fact]
    public async Task DeleteBot_RemovesBotProfileAndSafeData_ButKeepsMessageHistory()
    {
        await using var database = new SqliteTestDatabase();
        await using var dbContext = await database.CreateContextAsync();

        var owner = CreateUser("owner");
        var botUser = CreateUser("helperbot", isBot: true);
        botUser.Sessions.Add(new UserSession
        {
            UserId = botUser.Id,
            User = botUser,
            TokenHash = "bot-session"
        });
        botUser.PushDevices.Add(new PushDevice
        {
            UserId = botUser.Id,
            User = botUser,
            Platform = PushPlatform.Android,
            InstallationId = "bot-installation",
            DeviceToken = "bot-device-token",
            NotificationsEnabled = true
        });

        var bot = new Bot
        {
            Id = Guid.NewGuid(),
            UserId = botUser.Id,
            User = botUser,
            OwnerUserId = owner.Id,
            OwnerUser = owner,
            TokenHash = "bot-token"
        };
        var command = new BotCommand
        {
            BotId = bot.Id,
            Bot = bot,
            Command = "help",
            Description = "Show help"
        };

        var chat = CreateDirectChat(owner, botUser);
        var message = new Message
        {
            Id = Guid.NewGuid(),
            ChatId = chat.Id,
            Chat = chat,
            SenderId = botUser.Id,
            Sender = botUser,
            Text = "history",
            SentAt = new DateTimeOffset(2026, 5, 17, 12, 0, 0, TimeSpan.Zero)
        };
        chat.Messages.Add(message);
        var update = new BotUpdate
        {
            BotId = bot.Id,
            Bot = bot,
            ChatId = chat.Id,
            Chat = chat,
            MessageId = message.Id,
            Message = message,
            CreatedAt = message.SentAt
        };

        dbContext.AddRange(owner, botUser, bot, command, chat, update);
        await dbContext.SaveChangesAsync();

        var controller = ControllerTestFixture.CreateBotsController(dbContext, owner.Id);
        var response = await controller.DeleteBot(bot.Id, CancellationToken.None);

        Assert.IsType<NoContentResult>(response);
        Assert.False(await dbContext.Bots.AnyAsync(x => x.Id == bot.Id));
        Assert.False(await dbContext.BotCommands.AnyAsync(x => x.BotId == bot.Id));
        Assert.False(await dbContext.BotUpdates.AnyAsync(x => x.BotId == bot.Id));
        Assert.False(await dbContext.UserSessions.AnyAsync(x => x.UserId == botUser.Id));
        Assert.False(await dbContext.PushDevices.AnyAsync(x => x.UserId == botUser.Id));

        var reloadedBotUser = await dbContext.Users.SingleAsync(x => x.Id == botUser.Id);
        Assert.True(reloadedBotUser.IsBot);
        Assert.True(reloadedBotUser.IsBlocked);
        Assert.NotNull(reloadedBotUser.BlockedAt);

        var reloadedMessage = await dbContext.Messages.AsNoTracking().SingleAsync(x => x.Id == message.Id);
        Assert.Equal(botUser.Id, reloadedMessage.SenderId);
        Assert.Equal("history", reloadedMessage.Text);
    }

    [Fact]
    public async Task DeleteBot_ReturnsNotFoundForBotOwnedByAnotherUser()
    {
        await using var database = new SqliteTestDatabase();
        await using var dbContext = await database.CreateContextAsync();

        var owner = CreateUser("owner");
        var otherUser = CreateUser("other");
        var botUser = CreateUser("otherbot", isBot: true);
        var bot = new Bot
        {
            Id = Guid.NewGuid(),
            UserId = botUser.Id,
            User = botUser,
            OwnerUserId = owner.Id,
            OwnerUser = owner,
            TokenHash = "other-bot-token"
        };

        dbContext.AddRange(owner, otherUser, botUser, bot);
        await dbContext.SaveChangesAsync();

        var controller = ControllerTestFixture.CreateBotsController(dbContext, otherUser.Id);
        var response = await controller.DeleteBot(bot.Id, CancellationToken.None);

        Assert.IsType<NotFoundResult>(response);
        Assert.True(await dbContext.Bots.AnyAsync(x => x.Id == bot.Id));
    }

    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 CreateDirectChat(User first, User second)
    {
        var chat = new Chat
        {
            Id = Guid.NewGuid(),
            Type = ChatType.Direct,
            CreatedById = first.Id,
            CreatedBy = first,
            CreatedAt = new DateTimeOffset(2026, 5, 17, 11, 0, 0, TimeSpan.Zero)
        };
        chat.Members.Add(new ChatMember { ChatId = chat.Id, Chat = chat, UserId = first.Id, User = first });
        chat.Members.Add(new ChatMember { ChatId = chat.Id, Chat = chat, UserId = second.Id, User = second });
        return chat;
    }
}
