using MediatR;
using ChatService.Domain.AggregatesModel.ConversationAggregate;
using ChatService.Domain.AggregatesModel.UserAggregate;

namespace ChatService.API.Application.Commands.Conversations;

/// <summary>
/// EN: Handler for CreateConversationCommand.
/// VI: Handler cho CreateConversationCommand.
/// </summary>
public class CreateConversationCommandHandler : IRequestHandler<CreateConversationCommand, CreateConversationResult>
{
    private readonly IConversationRepository _conversationRepository;
    private readonly IChatUserRepository _chatUserRepository;
    private readonly ILogger<CreateConversationCommandHandler> _logger;

    public CreateConversationCommandHandler(
        IConversationRepository conversationRepository,
        IChatUserRepository chatUserRepository,
        ILogger<CreateConversationCommandHandler> logger)
    {
        _conversationRepository = conversationRepository;
        _chatUserRepository = chatUserRepository;
        _logger = logger;
    }

    public async Task<CreateConversationResult> Handle(CreateConversationCommand request, CancellationToken cancellationToken)
    {
        _logger.LogInformation("Creating conversation for creator {CreatorId} with {ParticipantCount} participants",
            request.CreatorId, request.ParticipantIds.Count());

        // EN: Validate all participants exist
        // VI: Kiểm tra tất cả participants tồn tại
        var allParticipantIds = request.ParticipantIds.Append(request.CreatorId).Distinct().ToList();
        var users = await _chatUserRepository.GetByIdsAsync(allParticipantIds, cancellationToken);
        var userDict = users.ToDictionary(u => u.Id);

        if (userDict.Count != allParticipantIds.Count)
        {
            var missingIds = allParticipantIds.Where(id => !userDict.ContainsKey(id));
            throw new InvalidOperationException($"ChatUsers not found: {string.Join(", ", missingIds)}");
        }

        Conversation conversation;

        // EN: Check for existing direct conversation
        // VI: Kiểm tra direct conversation đã tồn tại
        if (!request.IsGroup && request.ParticipantIds.Count() == 1)
        {
            var existingConversation = await _conversationRepository.FindDirectConversationAsync(
                request.CreatorId, request.ParticipantIds.First(), cancellationToken);

            if (existingConversation != null)
            {
                _logger.LogInformation("Found existing direct conversation {ConversationId}", existingConversation.Id);
                return CreateResult(existingConversation, userDict);
            }

            // EN: Create new direct conversation
            // VI: Tạo direct conversation mới
            conversation = Conversation.CreateDirect(request.CreatorId, request.ParticipantIds.First());
        }
        else
        {
            // EN: Create new group conversation
            // VI: Tạo group conversation mới
            conversation = Conversation.CreateGroup(
                request.Name ?? "Group Chat",
                request.CreatorId,
                request.ParticipantIds,
                request.AvatarUrl);
        }

        _conversationRepository.Add(conversation);
        await _conversationRepository.UnitOfWork.SaveEntitiesAsync(cancellationToken);

        _logger.LogInformation("Created conversation {ConversationId} of type {Type}",
            conversation.Id, conversation.Type.Name);

        return CreateResult(conversation, userDict);
    }

    private static CreateConversationResult CreateResult(Conversation conversation, Dictionary<Guid, ChatUser> userDict)
    {
        var participants = conversation.Participants.Select(p => new ParticipantDto(
            p.UserId,
            userDict.TryGetValue(p.UserId, out var user) ? user.DisplayName : "Unknown",
            userDict.TryGetValue(p.UserId, out var u) ? u.AvatarUrl : null,
            p.IsAdmin ? "admin" : "member"
        )).ToList();

        return new CreateConversationResult(
            conversation.Id,
            conversation.Type.Name,
            conversation.Name,
            participants,
            conversation.CreatedAt
        );
    }
}
