using CMSMicroservice.Domain.Events;
using CMSMicroservice.Domain.Enums;
using CMSMicroservice.Domain.Common;
using CMSMicroservice.Application.DayaLoanCQ.Services;
using CMSMicroservice.Application.Common.Interfaces;
using Microsoft.Extensions.Logging;

namespace CMSMicroservice.Application.DayaLoanCQ.Commands.CheckAndProcessDayaLoans;

/// <summary>
/// Handler یکپارچه برای استعلام و پردازش وام دایا
/// 1. استعلام از API دایا
/// 2. ذخیره/به‌روزرسانی DayaLoanContract
/// 3. شارژ کیف پول برای وام‌های تأیید شده
/// 4. ثبت Order پکیج
/// 5. ارسال SMS
/// </summary>
public class CheckAndProcessDayaLoansCommandHandler : IRequestHandler<CheckAndProcessDayaLoansCommand, CheckAndProcessDayaLoansResponseDto>
{
    private readonly IApplicationDbContext _context;
    private readonly IDayaLoanApiService _dayaApiService;
    private readonly IKavenegarService _smsService;
    private readonly ILogger<CheckAndProcessDayaLoansCommandHandler> _logger;

    public CheckAndProcessDayaLoansCommandHandler(
        IApplicationDbContext context,
        IDayaLoanApiService dayaApiService,
        IKavenegarService smsService,
        ILogger<CheckAndProcessDayaLoansCommandHandler> logger)
    {
        _context = context;
        _dayaApiService = dayaApiService;
        _smsService = smsService;
        _logger = logger;
    }

    public async Task<CheckAndProcessDayaLoansResponseDto> Handle(CheckAndProcessDayaLoansCommand request, CancellationToken cancellationToken)
    {
        var results = new List<DayaLoanProcessResult>();
        var processedCount = 0;
        
        try
        {
            // 1. استعلام از سرویس دایا
            _logger.LogInformation("Checking Daya loan status for {Count} national codes", request.NationalCodes.Count);
            var dayaResults = await _dayaApiService.CheckLoanStatusAsync(request.NationalCodes, cancellationToken);
            
            foreach (var dayaResult in dayaResults)
            {
                var result = new DayaLoanProcessResult
                {
                    NationalCode = dayaResult.NationalCode,
                    Status = dayaResult.Status,
                    ContractNumber = dayaResult.ContractNumber,
                    WasProcessed = false,
                    Message = "استعلام موفق"
                };
                
                try
                {
                    // 2. پیدا کردن کاربر
                    var user = await _context.Users
                        .Include(u => u.UserWallets)
                        .FirstOrDefaultAsync(u => u.NationalCode == dayaResult.NationalCode, cancellationToken);
                    
                    if (user == null)
                    {
                        result.Message = "کاربر یافت نشد";
                        results.Add(result);
                        continue;
                    }
                    
                    result.UserId = user.Id;
                    
                    // 2.5. بررسی محدودیت دایا — پس از اولین دور، فقط IPG مجاز است
                    var hasPreviousCycle = await _context.ClubMembershipCycles
                        .AnyAsync(c => c.UserId == user.Id, cancellationToken);

                    if (hasPreviousCycle)
                    {
                        result.Message = "کاربرانی که دور اول را تکمیل کرده‌اند فقط از طریق درگاه بانکی می‌توانند پکیج خریداری کنند";
                        results.Add(result);
                        continue;
                    }
                    
                    // 3. ذخیره/به‌روزرسانی DayaLoanContract
                    var contract = await _context.DayaLoanContracts
                        .FirstOrDefaultAsync(d => d.NationalCode == dayaResult.NationalCode, cancellationToken);
                    
                    if (contract == null)
                    {
                        contract = new DayaLoanContract
                        {
                            UserId = user.Id,
                            NationalCode = dayaResult.NationalCode,
                            Status = dayaResult.Status,
                            ContractNumber = dayaResult.ContractNumber,
                            LastCheckDate = DateTime.Now,
                            IsProcessed = false
                        };
                        await _context.DayaLoanContracts.AddAsync(contract, cancellationToken);
                    }
                    else
                    {
                        contract.Status = dayaResult.Status;
                        contract.ContractNumber = dayaResult.ContractNumber;
                        contract.LastCheckDate = DateTime.Now;
                    }
                    
                    // 4. آیا باید پردازش مالی انجام شود؟
                    var shouldProcess = !contract.IsProcessed &&
                                       !user.HasReceivedDayaCredit &&
                                       !string.IsNullOrEmpty(dayaResult.ContractNumber) &&
                                       (dayaResult.Status == DayaLoanStatus.PendingReceive || 
                                        dayaResult.Status == DayaLoanStatus.Received);
                    
                    if (shouldProcess)
                    {
                        // 5. پردازش مالی
                        var processResult = await ProcessDayaLoanAsync(user, dayaResult.ContractNumber!, cancellationToken);
                        
                        contract.IsProcessed = true;
                        result.WasProcessed = true;
                        result.NewWalletBalance = processResult.NewBalance;
                        result.PackageName = processResult.PackageName;
                        result.Message = "وام پردازش و کیف پول شارژ شد";
                        processedCount++;
                        
                        _logger.LogInformation(
                            "Daya loan processed for User {UserId}, Contract: {ContractNumber}, NewBalance: {Balance}",
                            user.Id, dayaResult.ContractNumber, processResult.NewBalance);
                    }
                    else if (contract.IsProcessed || user.HasReceivedDayaCredit)
                    {
                        result.Message = "قبلاً پردازش شده";
                    }
                    else if (string.IsNullOrEmpty(dayaResult.ContractNumber))
                    {
                        result.Message = "هنوز قرارداد ندارد";
                    }
                    
                    await _context.SaveChangesAsync(cancellationToken);
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, "Error processing Daya loan for NationalCode {NationalCode}", dayaResult.NationalCode);
                    result.Message = $"خطا: {ex.Message}";
                }
                
                results.Add(result);
            }
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error calling Daya API service");
            
            // در صورت خطا در API
            foreach (var nationalCode in request.NationalCodes)
            {
                if (!results.Any(r => r.NationalCode == nationalCode))
                {
                    results.Add(new DayaLoanProcessResult
                    {
                        NationalCode = nationalCode,
                        Status = DayaLoanStatus.PendingReceive,
                        WasProcessed = false,
                        Message = $"خطا در استعلام: {ex.Message}"
                    });
                }
            }
        }
        
        return new CheckAndProcessDayaLoansResponseDto
        {
            Results = results,
            TotalChecked = request.NationalCodes.Count,
            WithContractCount = results.Count(r => !string.IsNullOrEmpty(r.ContractNumber)),
            ProcessedCount = processedCount
        };
    }

    /// <summary>
    /// پردازش مالی وام دایا
    /// </summary>
    private async Task<(long NewBalance, long TransactionId, string PackageName)> ProcessDayaLoanAsync(
        User user, 
        string contractNumber, 
        CancellationToken cancellationToken)
    {
        // بارگذاری پکیج پایه
        var package = await _context.Packages
            .FirstOrDefaultAsync(p => p.IsBasePackage && !p.IsDeleted, cancellationToken)
            ?? throw new InvalidOperationException("پکیج پایه یافت نشد");

        // 1. ایجاد تراکنش
        var transaction = new Transaction
        {
            Amount = package.Price,
            Description = $"دریافت اعتبار دایا - قرارداد {contractNumber}",
            PaymentStatus = PaymentStatus.Success,
            PaymentDate = DateTime.Now,
            RefId = contractNumber,
            Type = TransactionType.DepositExternal1
        };
        
        await _context.Transactions.AddAsync(transaction, cancellationToken);
        await _context.SaveChangesAsync(cancellationToken);
        
        // 2. یافتن یا ایجاد کیف پول
        var wallet = user.UserWallets.FirstOrDefault();
        if (wallet == null)
        {
            wallet = new UserWallet
            {
                UserId = user.Id,
                Balance = 0,
                NetworkBalance = 0,
                DiscountBalance = 0
            };
            await _context.UserWallets.AddAsync(wallet, cancellationToken);
            await _context.SaveChangesAsync(cancellationToken);
        }
        
        // 3. شارژ کیف پول عادی
        wallet.Balance += package.Price;
        
        var mainLog = new UserWalletHistory
        {
            WalletId = wallet.Id,
            CurrentBalance = 0,
            ChangeValue = package.Price,
            CurrentNetworkBalance = wallet.NetworkBalance,
            ChangeNerworkValue = 0,
            IsIncrease = true,
            RefrenceId = transaction.Id,
            PackageId = package.Id
        };
        await _context.UserWalletHistories.AddAsync(mainLog, cancellationToken);
        
        // 4. شارژ کیف پول تخفیف
        var discountAmount = (long)(package.Price * package.DiscountMultiplier);
        wallet.DiscountBalance += discountAmount;
        
        var discountLog = new UserWalletHistory
        {
            WalletId = wallet.Id,
            CurrentBalance = wallet.Balance,
            ChangeValue = 0,
            CurrentNetworkBalance = wallet.NetworkBalance,
            ChangeNerworkValue = 0,
            CurrentDiscountBalance = 0,
            ChangeDiscountValue = discountAmount,
            IsIncrease = true,
            RefrenceId = transaction.Id,
            PackageId = package.Id
        };
        await _context.UserWalletHistories.AddAsync(discountLog, cancellationToken);
        
        // 5. به‌روزرسانی کاربر
        user.HasReceivedDayaCredit = true;
        user.DayaCreditReceivedAt = DateTime.Now;
        user.PackagePurchaseMethod = PackagePurchaseMethod.DayaLoan;
        
        // 6. ثبت UserPackagePurchase برای پکیج پایه
        var packagePurchase = new UserPackagePurchase
        {
            UserId = user.Id,
            PackageId = package.Id,
            PurchaseMethod = PackagePurchaseMethod.DayaLoan,
            PurchasedAt = DateTime.Now,
            Amount = package.Price,
            TransactionId = transaction.Id
        };
        
        await _context.UserPackagePurchases.AddAsync(packagePurchase, cancellationToken);
        
        // 7. Domain Event
        user.AddDomainEvent(new DayaLoanApprovedEvent(user, transaction, contractNumber));
        
        await _context.SaveChangesAsync(cancellationToken);
        
        // 8. ارسال SMS
        await SendDayaLoanSmsAsync(user, package.Title);
        
        return (wallet.Balance, transaction.Id, package.Title);
    }
    
    /// <summary>
    /// ارسال SMS اطلاع‌رسانی
    /// </summary>
    private async Task SendDayaLoanSmsAsync(User user, string packageName)
    {
        try
        {
            var userName = SmsTemplates.GetUserName(user.FirstName+" "+user.LastName);
            var message = SmsTemplates.DayaLoanReceived(userName, packageName);
            
            await _smsService.SendAsync(user.Mobile, message);
            
            // ارسال SMS به ادمین برای اطلاع
            var adminMessage = $"وام دایا دریافت شد\nکاربر: {user.FirstName} {user.LastName}\nموبایل: {user.Mobile}\nکدملی: {user.NationalCode}\nپکیج: {packageName}";
            await _smsService.SendAsync("09199877503", adminMessage);
            
            _logger.LogInformation("Daya loan SMS sent to User {UserId}", user.Id);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to send Daya loan SMS to User {UserId}", user.Id);
        }
    }
}
