// EN: Repository implementation for BaristaQueueItem aggregate.
// VI: Trien khai repository cho aggregate BaristaQueueItem.

using Microsoft.EntityFrameworkCore;
using FnbEngine.Domain.AggregatesModel.BaristaAggregate;
using FnbEngine.Domain.SeedWork;

namespace FnbEngine.Infrastructure.Repositories;

/// <summary>
/// EN: Repository implementation for BaristaQueueItem aggregate.
/// VI: Trien khai repository cho aggregate BaristaQueueItem.
/// </summary>
public class BaristaQueueRepository : IBaristaQueueRepository
{
    private readonly FnbContext _context;

    public IUnitOfWork UnitOfWork => _context;

    public BaristaQueueRepository(FnbContext context)
    {
        _context = context ?? throw new ArgumentNullException(nameof(context));
    }

    /// <summary>
    /// EN: Add a new queue item.
    /// VI: Them item moi vao hang doi.
    /// </summary>
    public async Task<BaristaQueueItem> AddAsync(BaristaQueueItem item, CancellationToken cancellationToken = default)
    {
        return (await _context.BaristaQueueItems.AddAsync(item, cancellationToken)).Entity;
    }

    /// <summary>
    /// EN: Update an existing queue item.
    /// VI: Cap nhat item hang doi hien tai.
    /// </summary>
    public void Update(BaristaQueueItem item)
    {
        _context.Entry(item).State = EntityState.Modified;
    }

    /// <summary>
    /// EN: Get queue item by ID.
    /// VI: Lay item hang doi theo ID.
    /// </summary>
    public async Task<BaristaQueueItem?> GetByIdAsync(Guid id, CancellationToken cancellationToken = default)
    {
        return await _context.BaristaQueueItems
            .FirstOrDefaultAsync(bq => bq.Id == id, cancellationToken);
    }

    /// <summary>
    /// EN: Get active queue items (Queued, Preparing, Ready) for a shop, sorted by priority desc then createdAt asc.
    /// VI: Lay cac item dang hoat dong (Cho, Dang pha, San sang) cho shop, sap xep theo uu tien giam roi thoi gian tao tang.
    /// </summary>
    public async Task<IEnumerable<BaristaQueueItem>> GetActiveByShopAsync(Guid shopId, CancellationToken cancellationToken = default)
    {
        return await _context.BaristaQueueItems
            .Where(bq => EF.Property<Guid>(bq, "_shopId") == shopId
                      && (EF.Property<int>(bq, "_statusId") == 1  // Queued
                       || EF.Property<int>(bq, "_statusId") == 2  // Preparing
                       || EF.Property<int>(bq, "_statusId") == 3)) // Ready
            .OrderByDescending(bq => EF.Property<int>(bq, "_priority"))
            .ThenBy(bq => EF.Property<DateTime>(bq, "_createdAt"))
            .ToListAsync(cancellationToken);
    }

    /// <summary>
    /// EN: Get all queue items for a shop (including completed).
    /// VI: Lay tat ca item hang doi cho shop (bao gom da hoan thanh).
    /// </summary>
    public async Task<IEnumerable<BaristaQueueItem>> GetByShopAsync(Guid shopId, CancellationToken cancellationToken = default)
    {
        return await _context.BaristaQueueItems
            .Where(bq => EF.Property<Guid>(bq, "_shopId") == shopId)
            .OrderByDescending(bq => EF.Property<DateTime>(bq, "_createdAt"))
            .ToListAsync(cancellationToken);
    }

    /// <summary>
    /// EN: Get queue stats for a shop.
    /// VI: Lay thong ke hang doi cho shop.
    /// </summary>
    public async Task<BaristaQueueStats> GetStatsAsync(Guid shopId, CancellationToken cancellationToken = default)
    {
        var items = await _context.BaristaQueueItems
            .Where(bq => EF.Property<Guid>(bq, "_shopId") == shopId)
            .ToListAsync(cancellationToken);

        var totalQueued = items.Count(i => i.StatusId == 1);
        var totalPreparing = items.Count(i => i.StatusId == 2);
        var totalReady = items.Count(i => i.StatusId == 3);
        var totalDelivered = items.Count(i => i.StatusId == 4);
        var totalCancelled = items.Count(i => i.StatusId == 5);

        // EN: Calculate average prep time from items that have both start and completion times
        // VI: Tinh thoi gian pha che trung binh tu cac item co ca thoi gian bat dau va hoan thanh
        var completedWithTimes = items
            .Where(i => i.StartedAt.HasValue && i.CompletedAt.HasValue && i.StatusId != 5)
            .ToList();

        var avgPrepTime = completedWithTimes.Count > 0
            ? completedWithTimes.Average(i => (i.CompletedAt!.Value - i.StartedAt!.Value).TotalMinutes)
            : 0.0;

        return new BaristaQueueStats(
            totalQueued,
            totalPreparing,
            totalReady,
            totalDelivered,
            totalCancelled,
            Math.Round(avgPrepTime, 2));
    }
}
