namespace WalletService.API.Application.Commands;

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

/// <summary>
/// EN: Handler for AdminAdjustPointsCommand.
/// VI: Handler cho AdminAdjustPointsCommand.
/// </summary>
public class AdminAdjustPointsCommandHandler : IRequestHandler<AdminAdjustPointsCommand, AdminAdjustPointsResult>
{
    private readonly IPointAccountRepository _pointAccountRepository;
    private readonly ILogger<AdminAdjustPointsCommandHandler> _logger;

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

    public async Task<AdminAdjustPointsResult> Handle(
        AdminAdjustPointsCommand request, 
        CancellationToken cancellationToken)
    {
        var account = await _pointAccountRepository.GetByIdAsync(request.AccountId)
            ?? throw new WalletDomainException($"Point account {request.AccountId} not found");

        var previousPoints = account.AvailablePoints;

        // EN: Adjust points directly using domain method
        // VI: Điều chỉnh điểm trực tiếp bằng phương thức domain
        account.AdjustPoints(request.Points, $"Admin Adjustment: {request.Reason}");

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

        _logger.LogInformation(
            "Point account {AccountId} adjusted by Admin {AdminId}. Points: {Points}. Reason: {Reason}",
            request.AccountId, request.AdminId, request.Points, request.Reason);

        return new AdminAdjustPointsResult(
            account.Id,
            previousPoints,
            request.Points,
            account.AvailablePoints,
            request.Reason,
            DateTime.UtcNow);
    }
}

/// <summary>
/// EN: Handler for AdminGrantBonusCommand.
/// VI: Handler cho AdminGrantBonusCommand.
/// </summary>
public class AdminGrantBonusCommandHandler : IRequestHandler<AdminGrantBonusCommand, AdminGrantBonusResult>
{
    private readonly IPointAccountRepository _pointAccountRepository;
    private readonly ILogger<AdminGrantBonusCommandHandler> _logger;

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

    public async Task<AdminGrantBonusResult> Handle(
        AdminGrantBonusCommand request, 
        CancellationToken cancellationToken)
    {
        var account = await _pointAccountRepository.GetByIdAsync(request.AccountId)
            ?? throw new WalletDomainException($"Point account {request.AccountId} not found");

        var expiryMonths = request.ExpiryMonths ?? 12;
        var expiresAt = DateTime.UtcNow.AddMonths(expiryMonths);

        // EN: Earn bonus points with expiry
        // VI: Tích điểm thưởng với thời hạn
        account.AddBonusPoints(request.Points, "AdminBonus", $"Admin Bonus: {request.Reason}", expiresAt);

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

        _logger.LogInformation(
            "Point account {AccountId} granted {Points} bonus points by Admin {AdminId}. Reason: {Reason}",
            request.AccountId, request.Points, request.AdminId, request.Reason);

        return new AdminGrantBonusResult(
            account.Id,
            request.Points,
            account.AvailablePoints,
            expiresAt,
            DateTime.UtcNow);
    }
}
