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

namespace MembershipService.Infrastructure.Repositories;

/// <summary>
/// EN: Repository implementation for ExperienceTransaction.
/// VI: Repository implementation cho ExperienceTransaction.
/// </summary>
public class ExperienceTransactionRepository : IExperienceTransactionRepository
{
    private readonly MembershipServiceContext _context;

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

    public IUnitOfWork UnitOfWork => _context;

    /// <summary>
    /// EN: Get experience transaction by ID.
    /// VI: Lấy experience transaction theo ID.
    /// </summary>
    public async Task<ExperienceTransaction?> GetAsync(Guid id)
    {
        var transaction = await _context.ExperienceTransactions
            .FirstOrDefaultAsync(t => t.Id == id);
        
        if (transaction != null)
        {
            // EN: Set the Source enumeration based on SourceId
            // VI: Set Source enumeration dựa trên SourceId
            var source = ExperienceSource.FromValue<ExperienceSource>(transaction.SourceId);
            transaction.SetSource(source);
        }

        return transaction;
    }

    /// <summary>
    /// EN: Get paginated experience transactions for a member.
    /// VI: Lấy experience transactions phân trang cho một member.
    /// </summary>
    public async Task<IReadOnlyList<ExperienceTransaction>> GetByMemberIdAsync(
        Guid memberId, 
        int skip = 0, 
        int take = 20)
    {
        var transactions = await _context.ExperienceTransactions
            .Where(t => EF.Property<Guid>(t, "_memberId") == memberId)
            .OrderByDescending(t => EF.Property<DateTime>(t, "_createdAt"))
            .Skip(skip)
            .Take(take)
            .ToListAsync();

        // EN: Set Source for each transaction
        // VI: Set Source cho mỗi transaction
        foreach (var transaction in transactions)
        {
            var source = ExperienceSource.FromValue<ExperienceSource>(transaction.SourceId);
            transaction.SetSource(source);
        }

        return transactions;
    }

    /// <summary>
    /// EN: Get experience transactions by source for a member.
    /// VI: Lấy experience transactions theo nguồn cho một member.
    /// </summary>
    public async Task<IReadOnlyList<ExperienceTransaction>> GetBySourceAsync(
        Guid memberId, 
        ExperienceSource source)
    {
        var transactions = await _context.ExperienceTransactions
            .Where(t => EF.Property<Guid>(t, "_memberId") == memberId && 
                       EF.Property<int>(t, "_sourceId") == source.Id)
            .OrderByDescending(t => EF.Property<DateTime>(t, "_createdAt"))
            .ToListAsync();

        foreach (var transaction in transactions)
        {
            transaction.SetSource(source);
        }

        return transactions;
    }

    /// <summary>
    /// EN: Get total EXP points for a member.
    /// VI: Lấy tổng điểm EXP của một member.
    /// </summary>
    public async Task<int> GetTotalPointsByMemberIdAsync(Guid memberId)
    {
        return await _context.ExperienceTransactions
            .Where(t => EF.Property<Guid>(t, "_memberId") == memberId)
            .SumAsync(t => EF.Property<int>(t, "_points"));
    }

    /// <summary>
    /// EN: Get total EXP points by source for a member.
    /// VI: Lấy tổng điểm EXP theo nguồn cho một member.
    /// </summary>
    public async Task<int> GetTotalPointsBySourceAsync(Guid memberId, ExperienceSource source)
    {
        return await _context.ExperienceTransactions
            .Where(t => EF.Property<Guid>(t, "_memberId") == memberId && 
                       EF.Property<int>(t, "_sourceId") == source.Id)
            .SumAsync(t => EF.Property<int>(t, "_points"));
    }

    /// <summary>
    /// EN: Get transaction count for a member.
    /// VI: Lấy số lượng transactions của một member.
    /// </summary>
    public async Task<int> GetCountByMemberIdAsync(Guid memberId)
    {
        return await _context.ExperienceTransactions
            .Where(t => EF.Property<Guid>(t, "_memberId") == memberId)
            .CountAsync();
    }

    /// <summary>
    /// EN: Add new experience transaction.
    /// VI: Thêm experience transaction mới.
    /// </summary>
    public ExperienceTransaction Add(ExperienceTransaction transaction)
    {
        return _context.ExperienceTransactions.Add(transaction).Entity;
    }
}
