using Microsoft.EntityFrameworkCore;
using MissionService.Domain.AggregatesModel.RewardAggregate;
using MissionService.Domain.SeedWork;

namespace MissionService.Infrastructure.Repositories;

/// <summary>
/// EN: Repository implementation for UserReward aggregate
/// VI: Triển khai repository cho UserReward aggregate
/// </summary>
public class UserRewardRepository : IUserRewardRepository
{
    private readonly MissionDbContext _context;
    
    public IUnitOfWork UnitOfWork => _context;

    public UserRewardRepository(MissionDbContext context)
    {
        _context = context ?? throw new ArgumentNullException(nameof(context));
    }

    public UserReward Add(UserReward reward)
    {
        return _context.UserRewards.Add(reward).Entity;
    }

    public void Update(UserReward reward)
    {
        _context.Entry(reward).State = EntityState.Modified;
    }

    public async Task<UserReward?> GetByIdAsync(Guid id, CancellationToken ct = default)
    {
        return await _context.UserRewards.FindAsync(new object[] { id }, ct);
    }

    public async Task<IReadOnlyList<UserReward>> GetByUserIdAsync(Guid userId, CancellationToken ct = default)
    {
        return await _context.UserRewards
            .Where(r => r.UserId == userId)
            .OrderByDescending(r => r.EarnedAt)
            .ToListAsync(ct);
    }

    public async Task<IReadOnlyList<UserReward>> GetPendingByUserIdAsync(Guid userId, CancellationToken ct = default)
    {
        return await _context.UserRewards
            .Where(r => r.UserId == userId)
            .Where(r => r.Status == RewardStatus.Pending)
            .OrderByDescending(r => r.EarnedAt)
            .ToListAsync(ct);
    }

    public async Task<UserReward?> GetBySourceIdAsync(Guid sourceId, CancellationToken ct = default)
    {
        return await _context.UserRewards
            .FirstOrDefaultAsync(r => r.SourceId == sourceId, ct);
    }

    public async Task<decimal> SumClaimedPointsAsync(
        Guid userId,
        DateTime fromDate,
        DateTime toDate,
        CancellationToken ct = default)
    {
        return await _context.UserRewards
            .Where(r => r.UserId == userId)
            .Where(r => r.Status == RewardStatus.Claimed)
            .Where(r => r.ClaimedAt >= fromDate && r.ClaimedAt <= toDate)
            .SumAsync(r => r.Amount.Points + r.Amount.BonusPoints, ct);
    }

    public async Task<IReadOnlyList<UserReward>> GetExpiredUnclaimedAsync(CancellationToken ct = default)
    {
        var now = DateTime.UtcNow;
        
        return await _context.UserRewards
            .Where(r => r.Status == RewardStatus.Pending)
            .Where(r => r.ExpiresAt != null && r.ExpiresAt < now)
            .ToListAsync(ct);
    }
}
