using CMSMicroservice.Application.Common.Interfaces;
using CMSMicroservice.Application.Common.Models;
using MediatR;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;

namespace CMSMicroservice.Application.ManualPaymentCQ.Queries.GetAllManualPayments;

public class GetAllManualPaymentsQueryHandler 
    : IRequestHandler<GetAllManualPaymentsQuery, GetAllManualPaymentsResponseDto>
{
    private readonly IApplicationDbContext _context;
    private readonly ILogger<GetAllManualPaymentsQueryHandler> _logger;

    public GetAllManualPaymentsQueryHandler(
        IApplicationDbContext context,
        ILogger<GetAllManualPaymentsQueryHandler> logger)
    {
        _context = context;
        _logger = logger;
    }

    public async Task<GetAllManualPaymentsResponseDto> Handle(
        GetAllManualPaymentsQuery request,
        CancellationToken cancellationToken)
    {
        _logger.LogInformation(
            "Getting manual payments. Page: {Page}, PageSize: {PageSize}",
            request.PageNumber,
            request.PageSize
        );

        // ساخت Query با فیلترها
        var query = _context.ManualPayments
            .Include(m => m.User)
            .AsQueryable();

        // فیلتر UserId
        if (request.UserId.HasValue)
        {
            query = query.Where(m => m.UserId == request.UserId.Value);
        }

        // فیلتر Status
        if (request.Status.HasValue)
        {
            query = query.Where(m => m.Status == request.Status.Value);
        }

        // فیلتر Type
        if (request.Type.HasValue)
        {
            query = query.Where(m => m.Type == request.Type.Value);
        }

        // فیلتر RequestedBy
        if (request.RequestedBy.HasValue)
        {
            query = query.Where(m => m.RequestedBy == request.RequestedBy.Value);
        }

        // شمارش کل
        var totalCount = await query.CountAsync(cancellationToken);

        // مرتب‌سازی
        query = request.OrderByDescending
            ? query.OrderByDescending(m => m.Created)
            : query.OrderBy(m => m.Created);

        // Pagination
        var skip = (request.PageNumber - 1) * request.PageSize;
        
        // دریافت PackageName پیش‌فرض از آخرین خرید پکیج کاربر (fallback برای داده‌های قدیمی)
        var userPackageNames = await _context.UserPackagePurchases
            .Include(p => p.Package)
            .GroupBy(p => p.UserId)
            .Select(g => new { UserId = g.Key, PackageName = g.OrderByDescending(x => x.PurchasedAt).First().Package.Title })
            .ToDictionaryAsync(x => x.UserId, x => x.PackageName, cancellationToken);
        
        var data = await query
            .Skip(skip)
            .Take(request.PageSize)
            .Select(m => new ManualPaymentDto
            {
                Id = m.Id,
                UserId = m.UserId,
                UserFullName = m.User.FirstName + " " + m.User.LastName,
                UserMobile = m.User.Mobile ?? "",
                Amount = m.Amount,
                Type = m.Type,
                TypeDisplay = m.Type.ToString(),
                Description = m.Description,
                ReferenceNumber = m.ReferenceNumber,
                Status = m.Status,
                StatusDisplay = m.Status.ToString(),
                RequestedBy = m.RequestedBy,
                RequestedByName = "", // باید از جدول User گرفته شود
                ApprovedBy = m.ApprovedBy,
                ApprovedByName = null,
                ApprovedAt = m.ApprovedAt,
                RejectionReason = m.RejectionReason,
                TransactionId = m.TransactionId,
                Created = m.Created
            })
            .ToListAsync(cancellationToken);

        // PackageName دقیق هر پرداخت دستی از UserWalletHistories بر اساس TransactionId همان پرداخت
        var transactionIds = data
            .Where(x => x.TransactionId.HasValue)
            .Select(x => x.TransactionId!.Value)
            .Distinct()
            .ToList();

        var packageNamesByTransaction = new Dictionary<long, string>();
        if (transactionIds.Count > 0)
        {
            packageNamesByTransaction = await _context.UserWalletHistories
                .AsNoTracking()
                .Include(h => h.Package)
                .Where(h => h.RefrenceId.HasValue
                    && transactionIds.Contains(h.RefrenceId.Value)
                    && h.PackageId.HasValue)
                .GroupBy(h => h.RefrenceId!.Value)
                .Select(g => new
                {
                    TransactionId = g.Key,
                    PackageName = g.OrderByDescending(x => x.Created)
                        .Select(x => x.Package != null ? x.Package.Title : string.Empty)
                        .FirstOrDefault()
                })
                .ToDictionaryAsync(x => x.TransactionId, x => x.PackageName ?? string.Empty, cancellationToken);
        }
        
        // تکمیل PackageName
        foreach (var item in data)
        {
            if (item.TransactionId.HasValue && packageNamesByTransaction.TryGetValue(item.TransactionId.Value, out var txPkgName))
            {
                item.PackageName = txPkgName;
            }
            else if (userPackageNames.TryGetValue(item.UserId, out var pkgName))
            {
                item.PackageName = pkgName;
            }
        }

        var metaData = new MetaData
        {
            TotalCount = totalCount,
            PageSize = request.PageSize,
            CurrentPage = request.PageNumber,
            TotalPage = (int)Math.Ceiling(totalCount / (double)request.PageSize),
            HasNext = request.PageNumber < (int)Math.Ceiling(totalCount / (double)request.PageSize),
            HasPrevious = request.PageNumber > 1
        };

        _logger.LogInformation(
            "Retrieved {Count} manual payments. Total: {Total}",
            data.Count,
            totalCount
        );

        return new GetAllManualPaymentsResponseDto
        {
            MetaData = metaData,
            Models = data
        };
    }
}
