using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.SignalR;
using Microsoft.Extensions.Logging;

namespace ColaFlow.Modules.Mcp.Infrastructure.Hubs;

/// <summary>
/// SignalR Hub for MCP real-time notifications
/// Supports notifying AI agents and users about PendingChange status updates
/// </summary>
[Authorize]
public class McpNotificationHub(ILogger<McpNotificationHub> logger) : Hub
{
    private readonly ILogger<McpNotificationHub> _logger = logger ?? throw new ArgumentNullException(nameof(logger));

    public override async Task OnConnectedAsync()
    {
        try
        {
            var connectionId = Context.ConnectionId;
            var userId = GetCurrentUserId();
            var tenantId = GetCurrentTenantId();

            // Automatically join tenant group (tenant isolation)
            await Groups.AddToGroupAsync(Context.ConnectionId, GetTenantGroupName(tenantId));

            _logger.LogInformation(
                "MCP client connected - ConnectionId={ConnectionId}, UserId={UserId}, TenantId={TenantId}",
                connectionId, userId, tenantId);

            await base.OnConnectedAsync();
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "MCP client connection error");
            Context.Abort();
        }
    }

    public override async Task OnDisconnectedAsync(Exception? exception)
    {
        var connectionId = Context.ConnectionId;

        if (exception != null)
        {
            _logger.LogError(exception,
                "MCP client disconnected with error - ConnectionId={ConnectionId}",
                connectionId);
        }
        else
        {
            _logger.LogInformation(
                "MCP client disconnected - ConnectionId={ConnectionId}",
                connectionId);
        }

        await base.OnDisconnectedAsync(exception);
    }

    /// <summary>
    /// Subscribe to receive notifications for a specific pending change
    /// </summary>
    /// <param name="pendingChangeId">The pending change ID to subscribe to</param>
    public async Task SubscribeToPendingChange(Guid pendingChangeId)
    {
        var groupName = GetPendingChangeGroupName(pendingChangeId);
        await Groups.AddToGroupAsync(Context.ConnectionId, groupName);

        _logger.LogInformation(
            "Client subscribed - ConnectionId={ConnectionId}, GroupName={GroupName}, PendingChangeId={PendingChangeId}",
            Context.ConnectionId, groupName, pendingChangeId);
    }

    /// <summary>
    /// Unsubscribe from receiving notifications for a specific pending change
    /// </summary>
    /// <param name="pendingChangeId">The pending change ID to unsubscribe from</param>
    public async Task UnsubscribeFromPendingChange(Guid pendingChangeId)
    {
        var groupName = GetPendingChangeGroupName(pendingChangeId);
        await Groups.RemoveFromGroupAsync(Context.ConnectionId, groupName);

        _logger.LogInformation(
            "Client unsubscribed - ConnectionId={ConnectionId}, GroupName={GroupName}, PendingChangeId={PendingChangeId}",
            Context.ConnectionId, groupName, pendingChangeId);
    }

    // Helper methods (copied from BaseHub to avoid cross-layer dependency)
    protected Guid GetCurrentUserId()
    {
        var userIdClaim = Context.User?.FindFirst("sub")
            ?? Context.User?.FindFirst("user_id");

        if (userIdClaim == null || !Guid.TryParse(userIdClaim.Value, out var userId))
        {
            throw new UnauthorizedAccessException("User ID not found in token");
        }

        return userId;
    }

    protected Guid GetCurrentTenantId()
    {
        var tenantIdClaim = Context.User?.FindFirst("tenant_id");

        if (tenantIdClaim == null || !Guid.TryParse(tenantIdClaim.Value, out var tenantId))
        {
            throw new UnauthorizedAccessException("Tenant ID not found in token");
        }

        return tenantId;
    }

    protected string GetTenantGroupName(Guid tenantId)
    {
        return $"tenant-{tenantId}";
    }

    private static string GetPendingChangeGroupName(Guid pendingChangeId)
    {
        return $"pending-change-{pendingChangeId}";
    }
}
