using Microsoft.Extensions.Logging; using PnvPanel.Application.Admin.Users; using PnvPanel.Application.Auth; using PnvPanel.Application.Billing; using PnvPanel.Application.Common.Interfaces; using PnvPanel.Application.Common.Messaging; using PnvPanel.Application.Common.Models; using PnvPanel.Domain.Audit; namespace PnvPanel.Application.Admin.Billing; public sealed class GrantBillingGiftCommandHandler( IAppDbContext dbContext, IIdentityService identityService, IXuiPanelGateway gateway, IRealtimeNotifier notifier, ITelegramNotifier telegramNotifier, ICurrentUser currentUser, ILogger logger ) : ICommandHandler { public async Task Handle(GrantBillingGiftCommand command, CancellationToken cancellationToken) { if (currentUser.UserId is not { } adminId) return Result.Failure(AuthErrors.Unauthorized); var profile = await identityService.GetProfileAsync(command.UserId, cancellationToken); if (profile is null) return Result.Failure(UserErrors.NotFound); if (!profile.BillingEnabled) return Result.Failure(BillingErrors.NotEnabled); var now = DateTimeOffset.UtcNow; var baseline = profile.BillingPaidUntil is { } paidUntil && paidUntil > now ? paidUntil : now; var newPaidUntil = baseline.AddDays(command.Days); var extendResult = await identityService.ExtendBillingPaidUntilAsync( command.UserId, newPaidUntil, cancellationToken ); if (!extendResult.IsSuccess) return extendResult; await BillingConfigResumer.ResumeConfigsAsync( dbContext, gateway, notifier, logger, command.UserId, newPaidUntil, cancellationToken ); dbContext.AuditLogs.Add( AuditLog.Create( adminId, "BillingGiftGranted", "User", command.UserId.ToString(), metadata: $"{{\"days\":{command.Days}}}", AuditSource.Web ) ); await telegramNotifier.NotifyUserAsync( command.UserId, $"🎁 Вам подарено {command.Days} дн. подписки! Доступ продлён до {newPaidUntil:dd.MM.yyyy}.", "/billing", cancellationToken ); return Result.Success(); } }