using Application.Abstractions.Hub;
using Infrastructure.Hubs;
using Web.Api.Common;
using Web.Api.Extensions;
using MediatR;
using Microsoft.AspNetCore.SignalR;
using Microsoft.EntityFrameworkCore;
using System.Security.Claims;

namespace Web.Api.Endpoints.Donation;

/// <summary>후원 전송</summary>
internal sealed class Send : IEndpoint
{
    public void MapEndpoint(IEndpointRouteBuilder app)
    {
        /// 후원 전송 (지갑 차감 → Donation 생성 → 알림 큐 → SignalR 브로드캐스트)
        app.MapPost("api/donation/send", async (
            Application.Features.Api.Donation.Send.Command body,
            ClaimsPrincipal user,
            ISender sender,
            IHubContext<AppHub, IAppHubClient> appHub,
            IHubContext<DonationHub, IDonationHubClient> donationHub,
            Application.Abstractions.Data.IAppDbContext db,
            CancellationToken ct
        ) => {
            var memberID = user.GetRequiredMemberID();
            var command = body with { SponsorMemberID = memberID };
            var data = await sender.Send(command, ct);

            // 크루 세션 후원인 경우 추가 브로드캐스트
            if (body.CrewSessionID.HasValue && body.CrewMemberID.HasValue)
            {
                // 크루 순위 업데이트 → DonationHub (OBS 위젯)
                var rankData = await sender.Send(
                    new Application.Features.Api.Crew.GetCrewRanking.Query(body.CrewSessionID.Value), ct
                );

                // 채널의 widgetToken 조회
                var channelID = body.ChannelID > 0 ? body.ChannelID :
                    (body.ChannelSID != null ?
                        await db.Channel.AsNoTracking().Where(c => c.SID == body.ChannelSID).Select(c => c.ID).FirstOrDefaultAsync(ct) : 0);

                var widgetToken = await db.Channel.AsNoTracking()
                    .Where(c => c.ID == channelID).Select(c => c.WidgetToken).FirstOrDefaultAsync(ct);

                if (!string.IsNullOrEmpty(widgetToken))
                {
                    await donationHub.Clients.Group(widgetToken).ReceiveCrewUpdate(new
                    {
                        rankData.List,
                        rankData.TotalAmount
                    });
                }

                // 크루원에게 토스트 알림 → AppHub
                var crewMember = await db.CrewMember.AsNoTracking()
                    .Where(m => m.ID == body.CrewMemberID.Value).FirstOrDefaultAsync(ct);

                if (crewMember is not null)
                {
                    await appHub.Clients.Group($"member:{crewMember.MemberID}").ReceiveCrewToast(new
                    {
                        SendName = body.SendName,
                        Amount = body.Amount,
                        Message = body.Message,
                        CrewMemberNickname = crewMember.Nickname
                    });
                }
            }

            return ApiResponse.Ok(data);
        })
        .WithTags("Donation")
        .RequireAuthorization();
    }
}