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

namespace CMSMicroservice.Application.ManualPaymentCQ.Commands.CreateManualPayment;

public class CreateManualPaymentCommandHandler : IRequestHandler<CreateManualPaymentCommand, long>
{
    private readonly IApplicationDbContext _context;
    private readonly ICurrentUserService _currentUser;
    private readonly ISender _sender;
    private readonly ILogger<CreateManualPaymentCommandHandler> _logger;

    public CreateManualPaymentCommandHandler(
        IApplicationDbContext context,
        ICurrentUserService currentUser,
        ISender sender,
        ILogger<CreateManualPaymentCommandHandler> logger)
    {
        _context = context;
        _currentUser = currentUser;
        _sender = sender;
        _logger = logger;
    }

    public async Task<long> Handle(
        CreateManualPaymentCommand request,
        CancellationToken cancellationToken)
    {
        try
        {
            _logger.LogInformation(
                "Creating manual membership payment for UserId: {UserId}, Type: {Type}",
                request.UserId,
                request.Type
            );

            // 1. بررسی Admin فعلی
            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.LogWarning("User not found: {UserId}", request.UserId);
                throw new NotFoundException(nameof(User), request.UserId);
            }

            // 3. پیدا کردن کیف پول
            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} یافت نشد");
            }

            // 4. بارگذاری پکیج انتخاب‌شده (یا پکیج پایه اگر PackageId=0)
            Domain.Entities.Package package;
            if (request.PackageId > 0)
            {
                package = await _context.Packages
                    .FirstOrDefaultAsync(p => p.Id == request.PackageId && !p.IsDeleted, cancellationToken)
                    ?? throw new NotFoundException($"پکیج با شناسه {request.PackageId} یافت نشد");
            }
            else
            {
                package = await _context.Packages
                    .FirstOrDefaultAsync(p => p.IsBasePackage && !p.IsDeleted, cancellationToken)
                    ?? throw new NotFoundException("پکیج پایه یافت نشد");
            }

            var balanceAmount = package.Price;
            var discountBalanceAmount = (long)(package.Price * package.DiscountMultiplier);
            

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

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

            // 6. ایجاد ManualPayment با وضعیت Approved (بدون نیاز به تایید دو مرحله‌ای)
            var manualPayment = new ManualPayment
            {
                UserId = request.UserId,
                Amount = balanceAmount,
                Type = request.Type,
                Description = request.Description,
                ReferenceNumber = request.ReferenceNumber,
                ImagePath = request.ImagePath,
                ImageDocumentId = request.ImageDocumentId,
                Status = ManualPaymentStatus.Approved,
                RequestedBy = adminUserId,
                ApprovedBy = adminUserId,
                ApprovedAt = DateTime.Now,
                TransactionId = transaction.Id
            };

            _context.ManualPayments.Add(manualPayment);

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

            wallet.Balance += balanceAmount;
            wallet.DiscountBalance += discountBalanceAmount;

            // 8. ثبت لاگ کیف پول
            var walletLog = new UserWalletHistory
            {
                WalletId = wallet.Id,
                CurrentBalance = 0,
                ChangeValue = balanceAmount,
                CurrentNetworkBalance = wallet.NetworkBalance,
                ChangeNerworkValue = 0,
                CurrentDiscountBalance =0,
                ChangeDiscountValue = discountBalanceAmount,
                IsIncrease = true,
                RefrenceId = transaction.Id,
                PackageId = package.Id
            };

            await _context.UserWalletHistories.AddAsync(walletLog, cancellationToken);

            // 9. تنظیم روش خرید پکیج + ثبت ledger خرید دستی
            user.PackagePurchaseMethod = PackagePurchaseMethod.Manual;

            _context.UserPackagePurchases.Add(new UserPackagePurchase
            {
                UserId = request.UserId,
                PackageId = package.Id,
                PurchaseMethod = PackagePurchaseMethod.Manual,
                PurchasedAt = DateTime.Now,
                Amount = balanceAmount,
                TransactionId = transaction.Id
            });

            // 10. ذخیره همه تغییرات
            await _context.SaveChangesAsync(cancellationToken);

            // 11. فعال‌سازی باشگاه مشتریان — ساخت Cycle و آماده‌سازی برای AcceptContract
            // این مرحله تضمین می‌کند که:
            //   الف) ClubMembershipCycle ساخته شود تا والدین امتیاز «عضو جدید» بگیرند
            //   ب) Pool توسط AcceptContract (که کاربر در FO امضا می‌کند) شارژ شود
            try
            {
                await _sender.Send(new ActivateClubMembershipCommand
                {
                    UserId = request.UserId,
                    ForceActivation = true,
                    PackageId = package.Id
                }, cancellationToken);
            }
            catch (Exception activateEx)
            {
                // عضویت باشگاه اختیاری است — خطا نباید پرداخت دستی را برگرداند
                _logger.LogWarning(
                    activateEx,
                    "Club membership activation failed after manual payment for UserId {UserId} — payment recorded successfully",
                    request.UserId
                );
            }

            _logger.LogInformation(
                "Manual membership payment created successfully. " +
                "ManualPaymentId: {Id}, UserId: {UserId}, TransactionId: {TransactionId}, " +
                "Balance: {OldBalance} -> {NewBalance}, DiscountBalance: {OldDiscount} -> {NewDiscount}",
                manualPayment.Id,
                request.UserId,
                transaction.Id,
                oldBalance,
                wallet.Balance,
                oldDiscountBalance,
                wallet.DiscountBalance
            );

            return manualPayment.Id;
        }
        catch (Exception ex) when (ex is not NotFoundException && ex is not UnauthorizedAccessException)
        {
            _logger.LogError(
                ex,
                "Error creating manual membership payment for UserId: {UserId}",
                request.UserId
            );
            throw;
        }
    }
}
