using Application.Abstractions.Data; using Application.Abstractions.Messaging; using Domain.Entities.Store.ValueObject; using Microsoft.EntityFrameworkCore; namespace Application.Features.Admin.Store.Coupon.Search; public sealed class Handler(IAppDbContext db) : IQueryHandler { public async Task Handle(Query request, CancellationToken ct) { var query = db.Coupon.AsNoTracking() .Include(c => c.Product) .Include(c => c.Game) .AsQueryable(); if (request.GameID.HasValue) { query = query.Where(c => c.GameID == request.GameID.Value); } if (request.ProductID.HasValue) { query = query.Where(c => c.ProductID == request.ProductID.Value); } if (!string.IsNullOrWhiteSpace(request.Keyword)) { var kw = request.Keyword.Trim(); query = query.Where(c => c.Name.Contains(kw)); } var total = await query.CountAsync(ct); var list = await query .OrderByDescending(c => c.ID) .Skip((request.Page - 1) * request.PerPage) .Take(request.PerPage) .Select(c => new { c.ID, c.ProductID, ProductName = c.Product!.Name, c.GameID, GameName = c.Game!.KorName, c.Name, c.UsagePolicy, c.ExpiresAt, c.GeneratedCount, c.UsedCount, AvailableCount = db.CouponCode.Count(cc => cc.CouponID == c.ID && cc.Status == CouponCodeStatus.Available), c.LowStockThreshold, c.UpdatedAt, c.CreatedAt }) .ToListAsync(ct); var startNum = total - ((request.Page - 1) * request.PerPage); return new Response( total, [.. list.Select((c, i) => new Response.Row( Num: startNum - i, c.ID, c.ProductID, c.ProductName, c.GameID, c.GameName, c.Name, c.UsagePolicy, c.ExpiresAt, c.GeneratedCount, c.UsedCount, c.AvailableCount, c.LowStockThreshold, IsLowStock: c.AvailableCount < c.LowStockThreshold, c.UpdatedAt, c.CreatedAt ))] ); } }