using Application.Abstractions.Data;
using Application.Abstractions.Messaging;
using Application.Abstractions.Paper;
using Application.Helpers;
using Microsoft.EntityFrameworkCore;
namespace Application.Features.Api.Paper.GetLeaderboard;
///
/// 모의투자 리더보드 (익명 허용) — Redis 캐시로 순위 페이지 조회 후 회원(SID/닉네임/썸네일)·지표 결합 (d4 M3 리더보드 백엔드 구현).
///
internal sealed class Handler(IAppDbContext db, IPaperLeaderboardCache cache) : IQueryHandler
{
private const int PageSize = 50;
public async Task Handle(Query request, CancellationToken ct)
{
var sort = PaperLeaderboardMetrics.ParseSort(request.Sort);
var period = PaperLeaderboardMetrics.ParsePeriod(request.Period);
var page = request.Page < 1 ? 1 : request.Page;
var minFillsForRank = await db.Config.AsNoTracking().OrderByDescending(c => c.ID).Select(c => c.Paper.MinFillsForRank).FirstOrDefaultAsync(ct);
if (minFillsForRank <= 0)
{
minFillsForRank = 3;
}
var offset = (page - 1) * PageSize;
var pageRows = await cache.GetPageAsync(sort, period, offset, PageSize, db, minFillsForRank, ct);
if (pageRows.Count == 0)
{
return new Response(PaperLeaderboardMetrics.SortToString(sort), PaperLeaderboardMetrics.PeriodToString(period), page, PageSize, []);
}
// 전체 지표 산출 후 memberID 로 매핑 (배치 리더보드 규모 소량 가정)
var metrics = await PaperLeaderboardMetrics.ComputeAllAsync(db, period, minFillsForRank, ct);
var metricByMember = metrics.ToDictionary(c => c.MemberID);
var memberIDs = pageRows.Select(c => c.MemberID).ToList();
var members = await db.Member.AsNoTracking()
.Where(c => memberIDs.Contains(c.ID))
.Select(c => new { c.ID, c.SID, c.Name, c.Thumb })
.ToListAsync(ct);
var memberByID = members.ToDictionary(c => c.ID);
var rows = new List(pageRows.Count);
foreach (var pr in pageRows)
{
if (!memberByID.TryGetValue(pr.MemberID, out var m))
{
continue;
}
metricByMember.TryGetValue(pr.MemberID, out var metric);
rows.Add(new Row(
pr.Rank + 1,
m.SID,
m.Name,
m.Thumb,
metric?.ReturnBp ?? 0,
metric?.WinRateBp ?? 0,
metric?.MddBp ?? 0,
metric?.FillCount ?? 0));
}
return new Response(PaperLeaderboardMetrics.SortToString(sort), PaperLeaderboardMetrics.PeriodToString(period), page, PageSize, rows);
}
}