namespace CMSMicroservice.Application.CommissionCQ.Queries.GetWithdrawalRequests;

public class GetWithdrawalRequestsQueryHandler : IRequestHandler<GetWithdrawalRequestsQuery, GetWithdrawalRequestsResponseDto>
{
    private readonly IApplicationDbContext _context;
    private readonly IWeekDefinitionRepository _weekDefinitionRepository;

    public GetWithdrawalRequestsQueryHandler(
        IApplicationDbContext context,
        IWeekDefinitionRepository weekDefinitionRepository)
    {
        _context = context;
        _weekDefinitionRepository = weekDefinitionRepository;
    }

    public async Task<GetWithdrawalRequestsResponseDto> Handle(GetWithdrawalRequestsQuery request, CancellationToken cancellationToken)
    {
        var query = _context.UserCommissionPayouts
            .AsNoTracking()
            .Include(x => x.User)
            .Include(x => x.WeekDefinition)
            .Where(x => x.WithdrawalMethod != null) // Only requests with withdrawal method
            .AsQueryable();

        // Filters
        if (request.Status.HasValue)
        {
            query = query.Where(x => (int)x.Status == request.Status.Value);
        }

        if (request.UserId.HasValue)
        {
            query = query.Where(x => x.UserId == request.UserId.Value);
        }

        if (request.WeekDefinitionId!= null && request.WeekDefinitionId >0)
        {
            query = query.Where(x => x.WeekDefinitionId == request.WeekDefinitionId);
        }

        if (!string.IsNullOrWhiteSpace(request.IbanNumber))
        {
            query = query.Where(x => x.IbanNumber != null && x.IbanNumber.Contains(request.IbanNumber));
        }

        query = query.ApplyOrder(sortBy: request.SortBy ?? "Created");

        var meta = await query.GetMetaData(request.PaginationState, cancellationToken);

        var models = await query
            .PaginatedListAsync(paginationState: request.PaginationState)
            .ToListAsync(cancellationToken);

        // دریافت PackageName از آخرین خرید پکیج کاربران
        var userIds = models.Select(x => x.UserId).Distinct().ToList();
        var userPackageNames = await _context.UserPackagePurchases
            .Where(p => userIds.Contains(p.UserId))
            .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 result = models.Select(x => new WithdrawalRequestModel
        {
            Id = x.Id,
            UserId = x.UserId,
            UserName = x.User != null ? (x.User.FirstName + " " + x.User.LastName).Trim() : x.User?.Mobile ?? "N/A",
            WeekDefinitionId = x.WeekDefinitionId,
            WeekDisplayName =x.WeekDefinition.DisplayName,
            Amount = x.TotalAmount,
            Status = (int)x.Status,
            WithdrawalMethod = x.WithdrawalMethod.HasValue ? (int)x.WithdrawalMethod.Value : 0,
            IbanNumber = x.IbanNumber,
            RequestedAt = x.WithdrawnAt ?? x.Created,
            ProcessedAt = x.LastModified,
            ProcessedBy = x.ProcessedBy,
            Reason = x.RejectionReason,
            BankReferenceId = x.BankReferenceId,
            BankTrackingCode = x.BankTrackingCode,
            PaymentFailureReason = x.PaymentFailureReason,
            Created = x.Created,
            PackageName = userPackageNames.GetValueOrDefault(x.UserId)
        }).ToList();

        return new GetWithdrawalRequestsResponseDto
        {
            MetaData = meta,
            Models = result
        };
    }
}
