namespace WalletService.API.Application.Commands;

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

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

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

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

        // EN: Spend points (may throw InsufficientPointsException)
        // VI: Tiêu điểm (có thể throw InsufficientPointsException)
        account.SpendPoints(request.Points, request.Source, request.Description);

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

        var transaction = account.Transactions.Last();

        _logger.LogInformation(
            "Spent {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
        );
    }
}
