using KArtSell.Modules.ModelOperations.ShadowRun.Events;
using Microsoft.AspNetCore.SignalR;
using Microsoft.Extensions.Logging;

namespace KArtSell.Host.Consumers;

/// <summary>
/// Pushes shadow run completion notifications via SignalR.
/// Targets group: model-{modelId} so all analysts tracking the model are notified.
/// Idempotent: SignalR deduplication via idempotency key.
/// </summary>
public sealed class ShadowRunCompletedConsumer : IInboxConsumer<ShadowRunCompletedEvent>
{
    private readonly IHubContext<ShadowRunHub>? _hubContext;
    private readonly ILogger<ShadowRunCompletedConsumer> _logger;

    private static readonly Action<ILogger, Guid, bool, Exception?> LogNotification =
        LoggerMessage.Define<Guid, bool>(
            LogLevel.Information,
            new EventId(1, nameof(LogNotification)),
            "Shadow run {RunId} notification sent; AllGatesPassed={AllGatesPassed}");

    private static readonly Action<ILogger, Exception?> LogHubNotConfigured =
        LoggerMessage.Define(
            LogLevel.Warning,
            new EventId(2, nameof(LogHubNotConfigured)),
            "SignalR hub not configured, skipping notification");

    public ShadowRunCompletedConsumer(
        IHubContext<ShadowRunHub>? hubContext,
        ILogger<ShadowRunCompletedConsumer> logger)
    {
        _hubContext = hubContext;
        _logger = logger;
    }

    public async Task HandleAsync(ShadowRunCompletedEvent message, CancellationToken cancellationToken = default)
    {
        try
        {
            LogNotification(_logger, message.RunId, message.AllGatesPassed, null);

            // If SignalR not configured, skip (e.g., in tests)
            if (_hubContext == null)
            {
                LogHubNotConfigured(_logger, null);
                return;
            }

            // Prepare notification payload
            var notification = new
            {
                message.RunId,
                message.ModelId,
                message.AllGatesPassed,
                message.TotalReturn,
                message.SharpeRatio,
                message.ProbOfBacktestOverfit,
                message.DailySharePercentile,
                message.ErrorMessage,
                message.CompletedAt
            };

            // Send to all clients in model group
            var groupName = $"model-{message.ModelId}";
            await _hubContext.Clients
                .Group(groupName)
                .SendAsync("ShadowRunCompleted", notification, cancellationToken);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to send shadow run notification for {RunId}", message.RunId);
            throw;  // Let Hangfire classify as transient/permanent
        }
    }
}

/// <summary>
/// SignalR hub for shadow run notifications.
/// Clients subscribe to group: model-{modelId}
/// </summary>
public sealed class ShadowRunHub : Hub
{
    private readonly ILogger<ShadowRunHub> _logger;

    public ShadowRunHub(ILogger<ShadowRunHub> logger)
    {
        _logger = logger;
    }

    public override async Task OnConnectedAsync()
    {
        _logger.LogInformation("Client {ConnectionId} connected to ShadowRunHub", Context.ConnectionId);
        await base.OnConnectedAsync();
    }

    public async Task SubscribeToModel(string modelId)
    {
        var groupName = $"model-{modelId}";
        await Groups.AddToGroupAsync(Context.ConnectionId, groupName);
        _logger.LogInformation(
            "Client {ConnectionId} subscribed to {Group}",
            Context.ConnectionId, groupName);
    }

    public async Task UnsubscribeFromModel(string modelId)
    {
        var groupName = $"model-{modelId}";
        await Groups.RemoveFromGroupAsync(Context.ConnectionId, groupName);
        _logger.LogInformation(
            "Client {ConnectionId} unsubscribed from {Group}",
            Context.ConnectionId, groupName);
    }
}
