using CMSMicroservice.Application.Common.Interfaces;
using CMSMicroservice.Application.Common.Models;
using CMSMicroservice.Domain.Enums;
using Microsoft.EntityFrameworkCore;

namespace CMSMicroservice.Application.UserPackagePurchaseCQ.Queries.GetCustomerPackagePurchaseRollup;

public class GetCustomerPackagePurchaseRollupQueryHandler
    : IRequestHandler<GetCustomerPackagePurchaseRollupQuery, GetCustomerPackagePurchaseRollupResponseDto>
{
    private readonly IApplicationDbContext _context;

    public GetCustomerPackagePurchaseRollupQueryHandler(IApplicationDbContext context)
    {
        _context = context;
    }

    public async Task<GetCustomerPackagePurchaseRollupResponseDto> Handle(
        GetCustomerPackagePurchaseRollupQuery request,
        CancellationToken cancellationToken)
    {
        var filter = request.Filter;
        var pagination = request.PaginationState ?? new PaginationState { PageNumber = 1, PageSize = 20 };
        if (pagination.PageNumber < 1) pagination.PageNumber = 1;
        // PageSize == 0 → خروجی کامل (بدون صفحه‌بندی)، مثلاً Excel
        var exportAll = pagination.PageSize == 0;
        if (!exportAll && pagination.PageSize < 1) pagination.PageSize = 20;

        // خرید معتبر: بدون تراکنش یا تراکنش موفق
        var purchases = _context.UserPackagePurchases
            .AsNoTracking()
            .Include(x => x.User)
            .Include(x => x.Package)
            .Include(x => x.Transaction)
            .Where(x => x.TransactionId == null
                        || (x.Transaction != null && x.Transaction.PaymentStatus == PaymentStatus.Success));

        if (filter?.UserId is > 0)
            purchases = purchases.Where(x => x.UserId == filter.UserId.Value);

        if (filter?.PurchaseMethod != null)
            purchases = purchases.Where(x => x.PurchaseMethod == filter.PurchaseMethod.Value);

        if (filter?.PurchasedFrom != null)
            purchases = purchases.Where(x => x.PurchasedAt >= filter.PurchasedFrom.Value);

        if (filter?.PurchasedTo != null)
            purchases = purchases.Where(x => x.PurchasedAt <= filter.PurchasedTo.Value);

        var rows = await purchases
            .Select(x => new
            {
                x.UserId,
                FirstName = x.User != null ? x.User.FirstName : null,
                LastName = x.User != null ? x.User.LastName : null,
                Mobile = x.User != null ? x.User.Mobile : null,
                x.PackageId,
                PackageName = x.Package != null ? x.Package.Title : null,
                x.Amount,
                x.PurchasedAt,
                x.PurchaseMethod
            })
            .ToListAsync(cancellationToken);

        var grouped = rows
            .GroupBy(x => x.UserId)
            .Select(g =>
            {
                var ordered = g.OrderBy(x => x.PurchasedAt).ThenBy(x => x.PackageId).ToList();
                var first = ordered.First();
                var last = ordered.Last();
                var userName = string.Join(" ",
                    new[] { first.FirstName, first.LastName }.Where(s => !string.IsNullOrWhiteSpace(s))).Trim();

                return new CustomerPackagePurchaseRollupModel
                {
                    UserId = g.Key,
                    UserName = string.IsNullOrWhiteSpace(userName)
                        ? (!string.IsNullOrWhiteSpace(first.Mobile) ? first.Mobile! : $"کاربر {g.Key}")
                        : userName,
                    UserMobile = first.Mobile ?? string.Empty,

                    FirstPackageId = first.PackageId,
                    FirstPackageName = first.PackageName ?? string.Empty,
                    FirstAmount = first.Amount,
                    FirstPurchasedAt = first.PurchasedAt,

                    LastPackageId = last.PackageId,
                    LastPackageName = last.PackageName ?? string.Empty,
                    LastAmount = last.Amount,
                    LastPurchasedAt = last.PurchasedAt,
                    LastPurchaseMethod = last.PurchaseMethod,

                    PurchaseCount = ordered.Count,
                    TotalAmount = ordered.Sum(x => x.Amount),

                    DayaCount = ordered.Count(x => x.PurchaseMethod == PackagePurchaseMethod.DayaLoan),
                    DayaAmount = ordered.Where(x => x.PurchaseMethod == PackagePurchaseMethod.DayaLoan).Sum(x => x.Amount),
                    ManualCount = ordered.Count(x => x.PurchaseMethod == PackagePurchaseMethod.Manual),
                    ManualAmount = ordered.Where(x => x.PurchaseMethod == PackagePurchaseMethod.Manual).Sum(x => x.Amount),
                    GatewayCount = ordered.Count(x => x.PurchaseMethod == PackagePurchaseMethod.DirectPurchase),
                    GatewayAmount = ordered.Where(x => x.PurchaseMethod == PackagePurchaseMethod.DirectPurchase).Sum(x => x.Amount)
                };
            })
            .OrderByDescending(x => x.LastPurchasedAt)
            .ToList();

        var totalCount = grouped.Count;
        var pageNumber = exportAll ? 1 : pagination.PageNumber;
        var pageSize = exportAll ? totalCount : pagination.PageSize;
        var totalPage = exportAll || pageSize <= 0
            ? (totalCount > 0 ? 1 : 0)
            : (int)Math.Ceiling(totalCount / (double)pageSize);

        var pageModels = exportAll
            ? grouped
            : grouped
                .Skip((pageNumber - 1) * pageSize)
                .Take(pageSize)
                .ToList();

        return new GetCustomerPackagePurchaseRollupResponseDto
        {
            MetaData = new MetaData
            {
                CurrentPage = pageNumber,
                PageSize = pageSize,
                TotalCount = totalCount,
                TotalPage = totalPage,
                HasPrevious = !exportAll && pageNumber > 1,
                HasNext = !exportAll && pageNumber < totalPage
            },
            Models = pageModels
        };
    }
}
