using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.SignalR;
using OpenIddict.Abstractions;

namespace foodmarket.Api.Realtime;

/// <summary>SignalR-хаб для live-уведомлений per-org. Группы именуются по
/// `OrganizationId` из JWT (claim <c>org_id</c>); при коннекте клиент
/// автоматически добавляется в свою группу, при дисконнекте — удаляется.
///
/// SuperAdmin с активным «Открыть как…» override'ом подписывается на группу
/// override-organization (так же как и обычный admin), чтобы видеть live-
/// события целевой org.
///
/// События отправляются методом <see cref="NotificationsPublisher"/>
/// (см. soседний файл). На клиенте имя метода = ключ в SignalR'е, типы
/// передаются JSON'ом — клиент описывает их сам.</summary>
[Authorize]
public sealed class NotificationsHub : Hub
{
    public override Task OnConnectedAsync()
    {
        var orgId = ResolveOrgId(Context);
        if (orgId is not null)
        {
            return Groups.AddToGroupAsync(Context.ConnectionId, GroupName(orgId.Value));
        }
        // Без org-id — соединение бесполезно (клиент не получит ничего); но
        // выкидывать не будем, может это setup-wizard у SuperAdmin'a.
        return Task.CompletedTask;
    }

    public override Task OnDisconnectedAsync(Exception? exception)
    {
        var orgId = ResolveOrgId(Context);
        if (orgId is not null)
        {
            return Groups.RemoveFromGroupAsync(Context.ConnectionId, GroupName(orgId.Value));
        }
        return Task.CompletedTask;
    }

    public static string GroupName(Guid orgId) => $"org:{orgId:N}";

    private static Guid? ResolveOrgId(HubCallerContext ctx)
    {
        // X-Org-Override (если SuperAdmin с активной маскировкой). Hub не
        // обрабатывает HTTP-заголовки автоматически — берём их из контекста.
        var http = ctx.GetHttpContext();
        if (http is not null && http.Request.Query.TryGetValue("orgOverride", out var qOverride)
            && Guid.TryParse(qOverride, out var ov))
        {
            return ov;
        }

        // Стандартный путь: org_id claim из JWT (см. AuthorizationController).
        var raw = ctx.User?.FindFirst("org_id")?.Value
                  ?? ctx.User?.FindFirst(OpenIddictConstants.Claims.Private.HostProperties)?.Value;
        return Guid.TryParse(raw, out var g) ? g : null;
    }
}
