using Application.Abstractions.Hub;
using Infrastructure.Hubs;
using Web.Api.Common;
using Web.Api.Extensions;
using MediatR;
using Microsoft.AspNetCore.SignalR;
using System.Security.Claims;
namespace Web.Api.Endpoints.Donation;
/// 리모콘 — 테스트 후원 (Wallet/PG 우회, IsTest 플래그로 통계 반영 여부 결정)
internal sealed class RemoteTestDonate : IEndpoint
{
public void MapEndpoint(IEndpointRouteBuilder app)
{
app.MapPost("api/donation/remote/test-donate", async (
TestDonateRequest body,
ClaimsPrincipal user,
ISender sender,
IHubContext donationHub,
Application.Abstractions.Data.IAppDbContext db,
CancellationToken ct
) => {
var memberID = user.GetRequiredMemberID();
var command = new Application.Features.Api.DonationRemote.TestDonate.Command(
WidgetToken: body.WidgetToken,
SendName: body.SendName,
Amount: body.Amount,
Message: body.Message,
CrewMemberID: body.CrewMemberID,
IsTest: body.IsTest,
RequesterMemberID: memberID
);
var result = await sender.Send(command, ct);
if (result.IsFailure)
{
return CustomResults.Problem(result);
}
var data = result.Value;
// SignalR broadcast — Alert 위젯
var alertPayload = new
{
alertID = data.AlertID,
donationID = data.DonationID,
correlationID = data.CorrelationID,
sponsorMemberID = memberID,
sendName = data.SendName,
amount = data.Amount,
netAmount = data.NetAmount,
message = data.Message,
channelID = data.ChannelID,
channelName = data.ChannelName,
crewMemberID = data.CrewMemberID,
crewMemberNickname = data.CrewMemberNickname,
isTest = data.IsTest,
createdAt = DateTime.UtcNow
};
await donationHub.Clients.Group(data.WidgetToken).ReceiveAlert(alertPayload);
// ⚠️ Goal/Rank/Crew broadcast는 알림 재생 종료 시점(DonationHub.AlertCompleted)에 처리됨
// 크루 후원이고 활성 세션이 있는 경우 — 크루 위젯 갱신
if (data.CrewSessionID.HasValue && data.CrewMemberID.HasValue)
{
var rankResult = await sender.Send(
new Application.Features.Api.Crew.GetCrewRanking.Query(data.CrewSessionID.Value), ct
);
if (rankResult.IsSuccess)
{
await donationHub.Clients.Group(data.WidgetToken).ReceiveCrewUpdate(new
{
rankResult.Value.List,
rankResult.Value.TotalAmount
});
}
}
return ApiResponse.Ok(data);
})
.WithTags("DonationRemote")
.RequireAuthorization();
}
public sealed record TestDonateRequest(
string WidgetToken,
string SendName,
int Amount,
string? Message,
int? CrewMemberID,
bool IsTest
);
}