namespace WalletService.API.Application.Commands;

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

/// <summary>
/// EN: Handler for WithdrawCommand.
/// VI: Handler cho WithdrawCommand.
/// </summary>
public class WithdrawCommandHandler : IRequestHandler<WithdrawCommand, TransactionResult>
{
    private readonly IWalletRepository _walletRepository;
    private readonly ILogger<WithdrawCommandHandler> _logger;

    public WithdrawCommandHandler(
        IWalletRepository walletRepository,
        ILogger<WithdrawCommandHandler> logger)
    {
        _walletRepository = walletRepository;
        _logger = logger;
    }

    public async Task<TransactionResult> Handle(
        WithdrawCommand request,
        CancellationToken cancellationToken)
    {
        var wallet = await _walletRepository.GetByUserIdAsync(request.UserId)
            ?? throw new WalletDomainException($"Wallet not found for user {request.UserId}");

        // EN: Use default currency type
        // VI: Sử dụng loại tiền tệ mặc định
        var currencyType = wallet.DefaultCurrencyType ?? CurrencyType.VND;

        // EN: Perform withdrawal with CurrencyType (may throw InsufficientBalanceException)
        // VI: Thực hiện rút tiền với CurrencyType (có thể throw InsufficientBalanceException)
        wallet.Withdraw(request.Amount, currencyType, request.Description, request.ReferenceId);

        _walletRepository.Update(wallet);
        await _walletRepository.UnitOfWork.SaveEntitiesAsync(cancellationToken);

        var transaction = wallet.Transactions.Last();

        _logger.LogInformation(
            "Withdrew {Amount} {Currency} from wallet {WalletId}",
            request.Amount, currencyType.Name, wallet.Id);

        return new TransactionResult(
            transaction.Id,
            wallet.Id,
            transaction.Amount.Amount,
            transaction.Amount.Currency,
            transaction.Type.Name,
            transaction.BalanceAfter,
            transaction.CreatedAt
        );
    }
}
