namespace WalletService.API.Application.Commands;

using MediatR;
using WalletService.Domain.AggregatesModel.PointAccountAggregate;
using WalletService.Domain.Exceptions;

/// <summary>
/// EN: Handler for EarnPointsCommand
/// VI: Handler cho EarnPointsCommand
/// </summary>
public class EarnPointsCommandHandler : IRequestHandler<EarnPointsCommand, PointTransactionResult>
{
    private readonly IPointAccountRepository _pointAccountRepository;
    private readonly ILogger<EarnPointsCommandHandler> _logger;

    public EarnPointsCommandHandler(
        IPointAccountRepository pointAccountRepository,
        ILogger<EarnPointsCommandHandler> logger)
    {
        _pointAccountRepository = pointAccountRepository;
        _logger = logger;
    }

    public async Task<PointTransactionResult> Handle(
        EarnPointsCommand request,
        CancellationToken cancellationToken)
    {
        var account = await _pointAccountRepository.GetByUserIdAsync(request.UserId)
            ?? throw new PointsDomainException($"Point account not found for user {request.UserId}");

        // EN: Calculate expiry date
        // VI: Tính ngày hết hạn
        DateTime? expiresAt = request.ExpiryMonths.HasValue
            ? DateTime.UtcNow.AddMonths(request.ExpiryMonths.Value)
            : null;

        // EN: Earn points
        // VI: Tích điểm
        account.EarnPoints(request.Points, request.Source, request.Description, expiresAt);

        _pointAccountRepository.Update(account);
        await _pointAccountRepository.UnitOfWork.SaveEntitiesAsync(cancellationToken);

        var transaction = account.Transactions.Last();

        _logger.LogInformation(
            "Earned {Points} points for user {UserId}, source: {Source}",
            request.Points, request.UserId, request.Source);

        return new PointTransactionResult(
            transaction.Id,
            account.Id,
            transaction.Points,
            transaction.Type.Name,
            transaction.BalanceAfter,
            transaction.CreatedAt,
            transaction.ExpiresAt
        );
    }
}
