namespace CMSMicroservice.Application.CommissionCQ.Queries.GetWeeklyCommissionPool;

public class GetWeeklyCommissionPoolQueryHandler : IRequestHandler<GetWeeklyCommissionPoolQuery, WeeklyCommissionPoolDto?>
{
    private readonly IApplicationDbContext _context;
    private readonly IWeekDefinitionRepository _weekDefinitionRepository;

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

    public async Task<WeeklyCommissionPoolDto?> Handle(GetWeeklyCommissionPoolQuery request, CancellationToken cancellationToken)
    {
        var query = _context.WeeklyCommissionPools  
            .Include(x => x.WeekDefinition)
            .Include(x => x.Package)
            .AsNoTracking()
            .Where(x => x.WeekDefinitionId == request.WeekDefinitionId);

        if (request.PackageId.HasValue)
            query = query.Where(x => x.PackageId == request.PackageId.Value);

        var pool = await query
            .Select(x => new WeeklyCommissionPoolDto
            {
                Id = x.Id,
                WeekDefinitionId = x.WeekDefinitionId,
                WeekDisplayName = x.WeekDefinition.DisplayName,
                TotalPoolAmount = x.TotalPoolAmount,
                TotalBalances = x.TotalBalances,
                ValuePerBalance = x.ValuePerBalance,
                IsCalculated = x.IsCalculated,
                CalculatedAt = x.CalculatedAt,
                Created = x.Created,
                PackageId = x.PackageId,
                PackageTitle = x.Package != null ? x.Package.Title : string.Empty
            })
            .FirstOrDefaultAsync(cancellationToken);

        pool ??= new WeeklyCommissionPoolDto();

        // ── Q29: اعتبارسنجی TotalPoolAmount در برابر فعال‌سازی‌های واقعی ──
        await ValidatePoolAmountAsync(pool, request, cancellationToken);

        return pool;
    }

    /// <summary>
    /// TotalPoolAmount استخر را با تعداد فعال‌سازی‌های ثبت‌شده (AcceptContract + ActivateClubMembership) مقایسه می‌کند.
    /// نتیجه در فیلدهای Validation... ذخیره می‌شود.
    /// </summary>
    private async Task ValidatePoolAmountAsync(WeeklyCommissionPoolDto pool, GetWeeklyCommissionPoolQuery request, CancellationToken cancellationToken)
    {
        var packageId = pool.PackageId > 0 ? pool.PackageId : request.PackageId;
        if (packageId is null or 0)
            return;

        var weekDef = _weekDefinitionRepository.GetWeekById(request.WeekDefinitionId);
        if (weekDef is null)
            return;

        var activationFee = await _context.Packages
            .AsNoTracking()
            .Where(p => p.Id == packageId.Value)
            .Select(p => p.ActivationFee)
            .FirstOrDefaultAsync(cancellationToken);

        if (activationFee <= 0)
            return;

        // شمارش Cycle‌هایی که Pool آن‌ها واقعاً شارژ شده:
        //   - عضو جدید: Pool توسط AcceptContract شارژ می‌شود → UserContract وجود دارد
        //   - خرید مجدد: Pool در ActivateClubMembership شارژ می‌شود → IsCurrentCycle نبوده (قبلاً active بوده)
        //   - نباید از IsActive استفاده شود: وضعیت تاریخی نیست (عضو ممکن است بعداً غیرفعال شده باشد)
        //
        // قانون: Cycle شارژ شده = یا قرارداد دارد (عضو جدید) یا IsActive قبلاً true بوده (خرید مجدد)
        // ساده‌ترین معادل: Cycle هایی که ClubMembership.ActivatedAt در بازه هفته است (زمان واقعی شارژ Pool)
        var totalActivations = await _context.ClubMembershipCycles
            .AsNoTracking()
            .Where(c => c.PackageId == packageId.Value
                && c.PackagePurchasedAt >= weekDef.StartDate
                && c.PackagePurchasedAt < weekDef.EndDate
                && _context.UserContracts.Any(uc =>
                    uc.UserId == c.UserId
                    && _context.Contracts.Any(con =>
                        con.Id == uc.ContractId
                        && con.Type == ContractType.ClubMembership)))
            .CountAsync(cancellationToken);

        var expectedAmount = (long)totalActivations * activationFee;

        pool.ValidationActivationCount = totalActivations;
        pool.ValidationExpectedAmount = expectedAmount;
        pool.ValidationDiscrepancy = pool.TotalPoolAmount - expectedAmount;
        pool.ValidationIsValid = pool.TotalPoolAmount == expectedAmount;
    }
}
