using Microsoft.EntityFrameworkCore;
using FacebookService.Domain.AggregatesModel.ConversationAggregate;
using FacebookService.Domain.SeedWork;

namespace FacebookService.Infrastructure.Repositories;

/// <summary>
/// EN: Repository implementation for Conversation aggregate.
/// VI: Triển khai repository cho Conversation aggregate.
/// </summary>
public class ConversationRepository : IConversationRepository
{
    private readonly FacebookServiceContext _context;

    public IUnitOfWork UnitOfWork => _context;

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

    /// <inheritdoc/>
    public async Task<Conversation?> GetByIdAsync(Guid id, CancellationToken cancellationToken = default)
    {
        return await _context.Conversations
            .Include(c => c.Status)
            .FirstOrDefaultAsync(c => c.Id == id, cancellationToken);
    }

    /// <inheritdoc/>
    public async Task<Conversation?> GetByIdWithMessagesAsync(Guid id, CancellationToken cancellationToken = default)
    {
        return await _context.Conversations
            .Include(c => c.Status)
            .Include(c => c.Messages)
                .ThenInclude(m => m.MessageType)
            .Include(c => c.Messages)
                .ThenInclude(m => m.Direction)
            .FirstOrDefaultAsync(c => c.Id == id, cancellationToken);
    }

    /// <inheritdoc/>
    public async Task<Conversation?> FindActiveByCustomerAndPageAsync(
        Guid customerId, 
        string pageId, 
        CancellationToken cancellationToken = default)
    {
        return await _context.Conversations
            .Include(c => c.Status)
            .FirstOrDefaultAsync(c => 
                EF.Property<Guid>(c, "_customerId") == customerId &&
                EF.Property<string>(c, "_pageId") == pageId &&
                c.StatusId == ConversationStatus.Active.Id, 
                cancellationToken);
    }

    /// <inheritdoc/>
    public async Task<IReadOnlyList<Conversation>> GetByCustomerIdAsync(
        Guid customerId, 
        CancellationToken cancellationToken = default)
    {
        return await _context.Conversations
            .Include(c => c.Status)
            .Where(c => EF.Property<Guid>(c, "_customerId") == customerId)
            .OrderByDescending(c => EF.Property<DateTime?>(c, "_lastMessageAt"))
            .ToListAsync(cancellationToken);
    }

    /// <inheritdoc/>
    public Conversation Add(Conversation conversation)
    {
        return _context.Conversations.Add(conversation).Entity;
    }

    /// <inheritdoc/>
    public void Update(Conversation conversation)
    {
        _context.Entry(conversation).State = EntityState.Modified;
    }
}
