namespace WalletService.API.Application.Commands;

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

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

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

    public async Task<TransactionResult> Handle(
        DepositCommand request,
        CancellationToken cancellationToken)
    {
        // EN: Get wallet by user ID
        // VI: Lấy ví theo user ID
        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 deposit with CurrencyType
        // VI: Thực hiện nạp tiền với CurrencyType
        wallet.Deposit(request.Amount, currencyType, request.Description, request.ReferenceId);

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

        // EN: Get the last transaction
        // VI: Lấy transaction cuối cùng
        var transaction = wallet.Transactions.Last();

        _logger.LogInformation(
            "Deposited {Amount} {Currency} to 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
        );
    }
}
