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 => "무효",
_ => "알수없음"
};
}