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

namespace WhatsAppService.Infrastructure.Repositories;

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

    public IUnitOfWork UnitOfWork => _context;

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

    public async Task<Conversation> AddAsync(Conversation conversation, CancellationToken cancellationToken = default)
    {
        var entry = await _context.Conversations.AddAsync(conversation, cancellationToken);
        return entry.Entity;
    }

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

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

    public async Task<Conversation?> GetActiveByCustomerAsync(Guid shopId, string customerWaId, CancellationToken cancellationToken = default)
    {
        return await _context.Conversations
            .Include(c => c.Status)
            .Include(c => c.Messages)
            .FirstOrDefaultAsync(c => 
                EF.Property<Guid>(c, "_shopId") == shopId &&
                EF.Property<string>(c, "_customerWaId") == customerWaId &&
                c.StatusId == ConversationStatus.Active.Id,
                cancellationToken);
    }

    public async Task<IReadOnlyList<Conversation>> GetByShopIdAsync(Guid shopId, int skip, int take, ConversationStatus? status = null, CancellationToken cancellationToken = default)
    {
        var query = _context.Conversations
            .Include(c => c.Status)
            .Where(c => EF.Property<Guid>(c, "_shopId") == shopId);

        if (status != null)
        {
            query = query.Where(c => c.StatusId == status.Id);
        }

        return await query
            .OrderByDescending(c => EF.Property<DateTime?>(c, "_lastMessageAt"))
            .Skip(skip)
            .Take(take)
            .ToListAsync(cancellationToken);
    }

    public async Task<IReadOnlyList<Conversation>> GetExpiredConversationsAsync(CancellationToken cancellationToken = default)
    {
        var now = DateTime.UtcNow;
        return await _context.Conversations
            .Include(c => c.Status)
            .Where(c => 
                c.StatusId == ConversationStatus.Active.Id &&
                EF.Property<DateTime?>(c, "_expiresAt") < now)
            .ToListAsync(cancellationToken);
    }
}
