using CMSMicroservice.Application.Common;
using CMSMicroservice.Application.Common.Exceptions;
using CMSMicroservice.Application.Common.Interfaces;
using CMSMicroservice.Domain.Entities;
using CMSMicroservice.Domain.Enums;
using MediatR;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;

namespace CMSMicroservice.Application.WalletCQ.Commands.AdminManualCreditCharge;

public class AdminManualCreditChargeCommandHandler
    : IRequestHandler<AdminManualCreditChargeCommand, AdminManualCreditChargeResult>
{
    private readonly IApplicationDbContext _context;
    private readonly ILogger<AdminManualCreditChargeCommandHandler> _logger;
    private readonly IUserPaymentLock _paymentLock;

    public AdminManualCreditChargeCommandHandler(
        IApplicationDbContext context,
        ILogger<AdminManualCreditChargeCommandHandler> logger,
        IUserPaymentLock paymentLock)
    {
        _context = context;
        _logger = logger;
        _paymentLock = paymentLock;
    }

    public Task<AdminManualCreditChargeResult> Handle(
        AdminManualCreditChargeCommand request,
        CancellationToken cancellationToken) =>
        _paymentLock.ExecuteAsync(
            PaymentLockScopes.Initiate(request.UserId),
            PaymentLockStrategy.FailFast,
            ct => HandleCore(request, ct),
            cancellationToken);

    private async Task<AdminManualCreditChargeResult> HandleCore(
        AdminManualCreditChargeCommand request,
        CancellationToken cancellationToken)
    {
        var user = await _context.Users
            .FirstOrDefaultAsync(u => u.Id == request.UserId, cancellationToken)
            ?? throw new NotFoundException(nameof(User), request.UserId);

        var wallet = await _context.UserWallets
            .FirstOrDefaultAsync(w => w.UserId == user.Id, cancellationToken)
            ?? throw new NotFoundException($"کیف پول کاربر با شناسه {request.UserId} یافت نشد");

        var oldBalance = wallet.Balance;
        wallet.Balance += request.Amount;

        var refId = $"MANUAL-{Guid.NewGuid():N}";
        var notePart = string.IsNullOrWhiteSpace(request.Note)
            ? string.Empty
            : $" — {request.Note.Trim()}";
        var adminPart = string.IsNullOrWhiteSpace(request.PerformedByAdminId)
            ? string.Empty
            : $" (ادمین: {request.PerformedByAdminId})";

        var transaction = new Transaction
        {
            Amount = request.Amount,
            Description = $"شارژ دستی کیف پول اصلی - کاربر {user.Id}{notePart}{adminPart}",
            PaymentStatus = PaymentStatus.Success,
            PaymentDate = DateTime.Now,
            RefId = refId,
            Type = TransactionType.ManualCreditWalletCharge
        };

        _context.Transactions.Add(transaction);
        await _context.SaveChangesAsync(cancellationToken);

        _context.UserWalletHistories.Add(new UserWalletHistory
        {
            WalletId = wallet.Id,
            CurrentBalance = wallet.Balance,
            ChangeValue = request.Amount,
            CurrentNetworkBalance = wallet.NetworkBalance,
            ChangeNerworkValue = 0,
            CurrentDiscountBalance = wallet.DiscountBalance,
            ChangeDiscountValue = 0,
            IsIncrease = true,
            RefrenceId = transaction.Id
        });
        await _context.SaveChangesAsync(cancellationToken);

        _logger.LogInformation(
            "Manual credit charge: UserId={UserId}, Amount={Amount}, OldBalance={Old}, NewBalance={New}, TxId={TxId}, Admin={Admin}",
            user.Id,
            request.Amount,
            oldBalance,
            wallet.Balance,
            transaction.Id,
            request.PerformedByAdminId);

        return new AdminManualCreditChargeResult
        {
            Success = true,
            Message = "شارژ دستی کیف پول اصلی با موفقیت انجام شد",
            TransactionId = transaction.Id,
            NewBalance = wallet.Balance
        };
    }
}
