using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using FluentAssertions;
using NSubstitute;
using Xunit;
using Knot.Shared.Kernel;
using Knot.Modules.Conversations.Domain;
using Knot.Modules.Messaging.Domain;
using Knot.Modules.Conversations.Application.Abstractions;
using Knot.Modules.Conversations.Application.Chats.GetChats;
using Knot.Modules.Conversations.Application.DTOs;

namespace Knot.Modules.Conversations.UnitTests.Chats;

public class GetChatsQueryHandlerTests
{
    private readonly IChatRepository _chatRepository;
    private readonly IUserDisplayNameProvider _userProvider;
    private readonly IMessageRepository _messageRepository;
    private readonly IMessageReactionRepository _reactionRepository;
    private readonly GetChatsQueryHandler _handler;

    public GetChatsQueryHandlerTests()
    {
        _chatRepository = Substitute.For<IChatRepository>();
        _userProvider = Substitute.For<IUserDisplayNameProvider>();
        _messageRepository = Substitute.For<IMessageRepository>();
        _reactionRepository = Substitute.For<IMessageReactionRepository>();

        _handler = new GetChatsQueryHandler(_chatRepository, _userProvider, _messageRepository, _reactionRepository);
    }

    [Fact]
    public async Task Handle_ShouldReturnUserChats_WhenTheyExist()
    {
        // Arrange
        var userId = Guid.NewGuid();
        var request = new GetChatsQuery(userId);

        var chat1 = Chat.Create("Test Chat", ChatType.Group);
        chat1.GetType().GetProperty("Id")?.SetValue(chat1, Guid.NewGuid());
        chat1.AddMember(userId, ChatRole.Owner);

        var chat2 = Chat.Create("Personal", ChatType.Personal);
        chat2.GetType().GetProperty("Id")?.SetValue(chat2, Guid.NewGuid());
        chat2.AddMember(userId, ChatRole.Member);

        _chatRepository.GetUserChatsAsync(userId, Arg.Any<CancellationToken>())
            .Returns(new List<Chat> { chat1, chat2 });

        _messageRepository.GetChatMessagesAsync(Arg.Any<Guid>(), 1, 0, Arg.Any<CancellationToken>())
            .Returns(new List<Message>());

        _userProvider.GetUsersInfoAsync(Arg.Any<IEnumerable<Guid>>(), Arg.Any<CancellationToken>())
            .Returns(new Dictionary<Guid, UserInfo>());

        // Act
        var result = await _handler.Handle(request, CancellationToken.None);

        // Assert
        result.IsSuccess.Should().BeTrue();
        result.Value.Should().NotBeNull();
        
        // It always appends synthetic "favorites" chat at the end if not found
        result.Value.Count.Should().Be(2); 
        result.Value.Any(c => c.Name == "Test Chat").Should().BeTrue();
        result.Value.Any(c => c.Type == "favorites").Should().BeTrue();
    }
}


