using Microsoft.EntityFrameworkCore;
using MembershipService.Domain.AggregatesModel.StampCardAggregate;
using MembershipService.Domain.SeedWork;

namespace MembershipService.Infrastructure.Repositories;

/// <summary>
/// EN: Repository implementation for StampCard aggregate.
/// VI: Repository implementation cho StampCard aggregate.
/// </summary>
public class StampCardRepository : IStampCardRepository
{
    private readonly MembershipServiceContext _context;

    public StampCardRepository(MembershipServiceContext context)
    {
        _context = context ?? throw new ArgumentNullException(nameof(context));
    }

    public IUnitOfWork UnitOfWork => _context;

    /// <summary>
    /// EN: Get stamp card by ID.
    /// VI: Lay stamp card theo ID.
    /// </summary>
    public async Task<StampCard?> GetByIdAsync(Guid id, CancellationToken cancellationToken = default)
    {
        return await _context.StampCards
            .FirstOrDefaultAsync(sc => sc.Id == id, cancellationToken);
    }

    /// <summary>
    /// EN: Get active stamp card (not completed, or completed but not claimed) for member+shop.
    /// VI: Lay stamp card dang hoat dong (chua hoan thanh, hoac hoan thanh nhung chua nhan thuong) cho member+shop.
    /// </summary>
    public async Task<StampCard?> GetActiveCardAsync(Guid shopId, Guid memberId, CancellationToken cancellationToken = default)
    {
        return await _context.StampCards
            .Where(sc => EF.Property<Guid>(sc, "_shopId") == shopId
                      && EF.Property<Guid>(sc, "_memberId") == memberId
                      && !EF.Property<bool>(sc, "_rewardClaimed"))
            .OrderByDescending(sc => EF.Property<DateTime>(sc, "_createdAt"))
            .FirstOrDefaultAsync(cancellationToken);
    }

    /// <summary>
    /// EN: Get stamp card by member and shop (most recent).
    /// VI: Lay stamp card theo member va shop (moi nhat).
    /// </summary>
    public async Task<StampCard?> GetByMemberAndShopAsync(Guid shopId, Guid memberId, CancellationToken cancellationToken = default)
    {
        return await _context.StampCards
            .Where(sc => EF.Property<Guid>(sc, "_shopId") == shopId
                      && EF.Property<Guid>(sc, "_memberId") == memberId)
            .OrderByDescending(sc => EF.Property<DateTime>(sc, "_createdAt"))
            .FirstOrDefaultAsync(cancellationToken);
    }

    /// <summary>
    /// EN: Get all stamp cards for a shop (admin view, paginated).
    /// VI: Lay tat ca stamp cards cho shop (admin view, phan trang).
    /// </summary>
    public async Task<(IEnumerable<StampCard> Cards, int TotalCount)> GetByShopAsync(
        Guid shopId,
        int pageIndex,
        int pageSize,
        CancellationToken cancellationToken = default)
    {
        var query = _context.StampCards
            .Where(sc => EF.Property<Guid>(sc, "_shopId") == shopId);

        var totalCount = await query.CountAsync(cancellationToken);

        var cards = await query
            .OrderByDescending(sc => EF.Property<DateTime>(sc, "_createdAt"))
            .Skip(pageIndex * pageSize)
            .Take(pageSize)
            .ToListAsync(cancellationToken);

        return (cards, totalCount);
    }

    /// <summary>
    /// EN: Add a new stamp card.
    /// VI: Them stamp card moi.
    /// </summary>
    public StampCard Add(StampCard stampCard)
    {
        return _context.StampCards.Add(stampCard).Entity;
    }

    /// <summary>
    /// EN: Update an existing stamp card.
    /// VI: Cap nhat stamp card hien tai.
    /// </summary>
    public void Update(StampCard stampCard)
    {
        _context.Entry(stampCard).State = EntityState.Modified;
    }
}
