using CMSMicroservice.Application.Common.Exceptions;
using CMSMicroservice.Application.Common.Interfaces;
using CMSMicroservice.Domain.Entities;
using CMSMicroservice.Domain.Entities.Payment;
using CMSMicroservice.Domain.Enums;
using Microsoft.EntityFrameworkCore;

namespace CMSMicroservice.Application.ManualPaymentCQ.Commands.ProcessManualMembershipPayment;

public class ProcessManualMembershipPaymentCommandHandler : IRequestHandler<ProcessManualMembershipPaymentCommand, ProcessManualMembershipPaymentResponseDto>
{
    private readonly IApplicationDbContext _context;
    private readonly ICurrentUserService _currentUser;
    private readonly ILogger<ProcessManualMembershipPaymentCommandHandler> _logger;

    public ProcessManualMembershipPaymentCommandHandler(
        IApplicationDbContext context,
        ICurrentUserService currentUser,
        ILogger<ProcessManualMembershipPaymentCommandHandler> logger)
    {
        _context = context;
        _currentUser = currentUser;
        _logger = logger;
    }

    public async Task<ProcessManualMembershipPaymentResponseDto> Handle(
        ProcessManualMembershipPaymentCommand request,
        CancellationToken cancellationToken)
    {
        try
        {
            _logger.LogInformation(
                "Processing manual membership payment for UserId: {UserId}, Amount: {Amount}",
                request.UserId, request.Amount);

            // 1. دریافت شناسه ادمین از کاربر جاری
            var currentUserId = _currentUser.UserId;
            if (string.IsNullOrEmpty(currentUserId))
            {
                throw new UnauthorizedAccessException("کاربر احراز هویت نشده است");
            }

            if (!long.TryParse(currentUserId, out var adminUserId))
            {
                throw new UnauthorizedAccessException("شناسه کاربر نامعتبر است");
            }

            // 2. بررسی وجود کاربر
            var user = await _context.Users
                .FirstOrDefaultAsync(u => u.Id == request.UserId, cancellationToken);

            if (user == null)
            {
                _logger.LogError("User not found: {UserId}", request.UserId);
                throw new NotFoundException($"کاربر با شناسه {request.UserId} یافت نشد");
            }

            // 3. ایجاد ManualPayment با وضعیت Approved
            var manualPayment = new ManualPayment
            {
                UserId = request.UserId,
                Amount = request.Amount,
                Type = ManualPaymentType.CashDeposit,
                Description = request.Description ?? "پرداخت دستی عضویت",
                ReferenceNumber = request.ReferenceNumber,
                Status = ManualPaymentStatus.Approved,
                RequestedBy = adminUserId,
                ApprovedBy = adminUserId,
                ApprovedAt = DateTime.Now
            };

            _context.ManualPayments.Add(manualPayment);
            await _context.SaveChangesAsync(cancellationToken);

            // 4. پیدا کردن یا ایجاد کیف پول
            var wallet = await _context.UserWallets
                .FirstOrDefaultAsync(w => w.UserId == request.UserId, cancellationToken);

            if (wallet == null)
            {
                _logger.LogError("Wallet not found for UserId: {UserId}", request.UserId);
                throw new NotFoundException($"کیف پول کاربر {request.UserId} یافت نشد");
            }

            // 6. ثبت تراکنش
            var transaction = new Transaction
            {
                Amount = request.Amount,
                Description = $"پرداخت دستی عضویت - {manualPayment.Description} - مرجع: {request.ReferenceNumber}",
                PaymentStatus = PaymentStatus.Success,
                PaymentDate = DateTime.Now,
                RefId = request.ReferenceNumber,
                Type = TransactionType.DepositExternal1
            };

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

            // 7. اعمال تغییرات بر کیف پول
            var oldBalance = wallet.Balance;
            var oldDiscountBalance = wallet.DiscountBalance;

            wallet.Balance += request.Amount;
            wallet.DiscountBalance += request.Amount;

            // 8. ثبت لاگ Balance
            var balanceLog = new UserWalletHistory
            {
                WalletId = wallet.Id,
                CurrentBalance = wallet.Balance,
                ChangeValue = request.Amount,
                CurrentNetworkBalance = wallet.NetworkBalance,
                ChangeNerworkValue = 0,
                CurrentDiscountBalance = wallet.DiscountBalance,
                ChangeDiscountValue = request.Amount,
                IsIncrease = true,
                RefrenceId = transaction.Id
            };
            await _context.UserWalletHistories.AddAsync(balanceLog, cancellationToken);

            user.PackagePurchaseMethod = PackagePurchaseMethod.Manual;
            // 10. به‌روزرسانی ManualPayment با TransactionId
            manualPayment.TransactionId = transaction.Id;
            await _context.SaveChangesAsync(cancellationToken);


            _logger.LogInformation(
                "Manual membership payment processed successfully. UserId: {UserId}, Amount: {Amount}, ManualPaymentId: {ManualPaymentId}, TransactionId: {TransactionId}, AdminUserId: {AdminUserId}",
                request.UserId, request.Amount, manualPayment.Id, transaction.Id, adminUserId);

            return new ProcessManualMembershipPaymentResponseDto
            {
                TransactionId = transaction.Id,
                NewWalletBalance = wallet.Balance,
                Message = "پرداخت دستی با موفقیت ثبت شد"
            };
        }
        catch (Exception ex) when (ex is not NotFoundException)
        {
            _logger.LogError(ex,
                "Error processing manual membership payment for UserId: {UserId}, Amount: {Amount}",
                request.UserId, request.Amount);
            throw;
        }
    }
}
