using Application.Abstractions.Data; using Application.Abstractions.Messaging; using Domain.Entities.Forum.Posts.ValueObject; using Microsoft.EntityFrameworkCore; using SharedKernel.Results; namespace Application.Features.Api.Forum.StockBoard.GetPrediction; /// 글의 예측 메타 + 채점 상태 (d2 §④ M2, 익명). 예측이 없으면 NotFound. internal sealed class Handler(IAppDbContext db) : IQueryHandler> { public async Task> Handle(Query request, CancellationToken ct) { var prediction = await db.PostPrediction.AsNoTracking() .Where(c => c.PostID == request.PostID) .Select(c => new { c.PostID, c.MemberID, c.StockCode, c.Direction, c.BasePrice, c.TargetPrice, c.HorizonDays, c.DueDate, c.Status, c.SettledPrice, c.SettledAt, c.CreatedAt }) .FirstOrDefaultAsync(ct); if (prediction is null) { return Result.Failure(Error.NotFound("Prediction.NotFound", "예측 정보를 찾을 수 없습니다.")); } var stockName = await db.Stock.AsNoTracking().Where(c => c.Code == prediction.StockCode).Select(c => c.Name).FirstOrDefaultAsync(ct); return new Response( prediction.PostID, prediction.MemberID, prediction.StockCode, stockName, (byte)prediction.Direction, DirectionLabel(prediction.Direction), prediction.BasePrice, prediction.TargetPrice, prediction.HorizonDays, prediction.DueDate, (byte)prediction.Status, StatusLabel(prediction.Status), prediction.SettledPrice, prediction.SettledAt, prediction.CreatedAt); } private static string DirectionLabel(PredictionDirection direction) => direction switch { PredictionDirection.Up => "상승", PredictionDirection.Down => "하락", _ => "알수없음" }; private static string StatusLabel(PredictionStatus status) => status switch { PredictionStatus.Pending => "채점대기", PredictionStatus.Hit => "적중", PredictionStatus.Miss => "실패", PredictionStatus.Void => "무효", _ => "알수없음" }; }