using MediatR;
using Microsoft.EntityFrameworkCore;
using FacebookService.API.Application.Dtos;
using FacebookService.Domain.AggregatesModel.ConversationAggregate;
using FacebookService.Domain.AggregatesModel.CustomerAggregate;
using FacebookService.Infrastructure;

namespace FacebookService.API.Application.Queries;

/// <summary>
/// EN: Handler for GetConversationsQuery - returns paginated conversations list.
/// VI: Handler cho GetConversationsQuery - trả về danh sách conversations phân trang.
/// </summary>
public class GetConversationsQueryHandler : IRequestHandler<GetConversationsQuery, GetConversationsQueryResult>
{
    private readonly FacebookServiceContext _context;

    public GetConversationsQueryHandler(FacebookServiceContext context)
    {
        _context = context ?? throw new ArgumentNullException(nameof(context));
    }

    public async Task<GetConversationsQueryResult> Handle(
        GetConversationsQuery request,
        CancellationToken cancellationToken)
    {
        // EN: Build base query with status inclusion / VI: Xây dựng query cơ bản với status
        var query = _context.Conversations
            .AsNoTracking()
            .Include(c => c.Status)
            .AsQueryable();

        // EN: Filter by page ID (shop) if provided / VI: Lọc theo page ID (shop) nếu có
        if (request.ShopId.HasValue)
        {
            var pageId = request.ShopId.Value.ToString();
            query = query.Where(c => EF.Property<string>(c, "_pageId") == pageId);
        }

        // EN: Filter by status if provided / VI: Lọc theo status nếu có
        if (!string.IsNullOrEmpty(request.Status))
        {
            var statusId = request.Status.ToLower() switch
            {
                "active" => ConversationStatus.Active.Id,
                "closed" => ConversationStatus.Closed.Id,
                "archived" => ConversationStatus.Archived.Id,
                _ => 0
            };
            if (statusId > 0)
                query = query.Where(c => c.StatusId == statusId);
        }

        // EN: Get total count for pagination / VI: Lấy tổng số cho phân trang
        var totalCount = await query.CountAsync(cancellationToken);

        // EN: Get paginated conversations ordered by last message time
        // VI: Lấy conversations phân trang sắp xếp theo thời gian tin nhắn cuối
        var conversations = await query
            .OrderByDescending(c => EF.Property<DateTime?>(c, "_lastMessageAt"))
            .Skip(request.Skip)
            .Take(request.Take)
            .ToListAsync(cancellationToken);

        // EN: Load customer names for summaries / VI: Tải tên khách hàng cho tóm tắt
        var customerIds = conversations.Select(c => c.CustomerId).Distinct().ToList();
        var customers = await _context.Customers
            .AsNoTracking()
            .Where(c => customerIds.Contains(c.Id))
            .ToDictionaryAsync(c => c.Id, c => c.Name, cancellationToken);

        // EN: Map to summary DTOs / VI: Map sang DTO tóm tắt
        var summaries = conversations.Select(c =>
        {
            customers.TryGetValue(c.CustomerId, out var customerName);
            var lastMessage = c.Messages.OrderByDescending(m => m.SentAt).FirstOrDefault();

            return new ConversationSummaryDto(
                c.Id,
                c.CustomerId,
                customerName,
                c.PageId,
                c.Status.Name,
                lastMessage?.Content,
                c.LastMessageAt,
                c.CreatedAt);
        }).ToList();

        return new GetConversationsQueryResult(summaries, totalCount);
    }
}

/// <summary>
/// EN: Handler for GetConversationByIdQuery.
/// VI: Handler cho GetConversationByIdQuery.
/// </summary>
public class GetConversationByIdQueryHandler : IRequestHandler<GetConversationByIdQuery, ConversationDto?>
{
    private readonly IConversationRepository _conversationRepository;

    public GetConversationByIdQueryHandler(IConversationRepository conversationRepository)
    {
        _conversationRepository = conversationRepository ?? throw new ArgumentNullException(nameof(conversationRepository));
    }

    public async Task<ConversationDto?> Handle(
        GetConversationByIdQuery request,
        CancellationToken cancellationToken)
    {
        Conversation? conversation;

        if (request.IncludeMessages)
        {
            conversation = await _conversationRepository.GetByIdWithMessagesAsync(
                request.ConversationId, cancellationToken);
        }
        else
        {
            conversation = await _conversationRepository.GetByIdAsync(
                request.ConversationId, cancellationToken);
        }

        if (conversation is null)
        {
            return null;
        }

        return MapToDto(conversation, request.IncludeMessages);
    }

    private static ConversationDto MapToDto(Conversation conversation, bool includeMessages)
    {
        var messages = includeMessages 
            ? conversation.Messages.OrderBy(m => m.SentAt).Select(MapMessageToDto).ToList()
            : null;

        return new ConversationDto(
            conversation.Id,
            conversation.CustomerId,
            Customer: null, // EN: Not loaded here / VI: Không load ở đây
            conversation.PageId,
            conversation.Status.Name,
            conversation.Channel,
            conversation.AssignedAgentId,
            conversation.LastMessageAt,
            conversation.CreatedAt,
            messages
        );
    }

    private static MessageDto MapMessageToDto(Message message)
    {
        return new MessageDto(
            message.Id,
            message.SenderId,
            message.Content,
            message.MessageType.Name,
            message.Direction.Name,
            message.SentAt,
            message.FacebookMessageId,
            message.Metadata
        );
    }
}
