using ColaFlow.Modules.Mcp.Application.DTOs.Notifications;
using ColaFlow.Modules.Mcp.Application.Services;
using ColaFlow.Modules.Mcp.Infrastructure.Hubs;
using Microsoft.AspNetCore.SignalR;
using Microsoft.Extensions.Logging;

namespace ColaFlow.Modules.Mcp.Infrastructure.Services;

/// <summary>
/// Implementation of IMcpNotificationService using SignalR
/// </summary>
public class McpNotificationService(
    IHubContext<McpNotificationHub> hubContext,
    ILogger<McpNotificationService> logger)
    : IMcpNotificationService
{
    private readonly IHubContext<McpNotificationHub> _hubContext = hubContext ?? throw new ArgumentNullException(nameof(hubContext));
    private readonly ILogger<McpNotificationService> _logger = logger ?? throw new ArgumentNullException(nameof(logger));

    public async Task NotifyPendingChangeCreatedAsync(
        PendingChangeCreatedNotification notification,
        CancellationToken cancellationToken = default)
    {
        var groupName = GetPendingChangeGroupName(notification.PendingChangeId);
        var tenantGroupName = GetTenantGroupName(notification.TenantId);

        _logger.LogInformation(
            "Sending PendingChangeCreated notification - PendingChangeId={PendingChangeId}, EntityType={EntityType}, Operation={Operation}",
            notification.PendingChangeId, notification.EntityType, notification.Operation);

        // Send to both: specific pending change subscribers AND all tenant members
        await _hubContext.Clients
            .Groups(groupName, tenantGroupName)
            .SendAsync("PendingChangeCreated", notification, cancellationToken);

        _logger.LogDebug(
            "PendingChangeCreated notification sent - Groups=[{GroupName}, {TenantGroupName}]",
            groupName, tenantGroupName);
    }

    public async Task NotifyPendingChangeApprovedAsync(
        PendingChangeApprovedNotification notification,
        CancellationToken cancellationToken = default)
    {
        var groupName = GetPendingChangeGroupName(notification.PendingChangeId);
        var tenantGroupName = GetTenantGroupName(notification.TenantId);

        _logger.LogInformation(
            "Sending PendingChangeApproved notification - PendingChangeId={PendingChangeId}, EntityType={EntityType}, ApprovedBy={ApprovedBy}",
            notification.PendingChangeId, notification.EntityType, notification.ApprovedBy);

        await _hubContext.Clients
            .Groups(groupName, tenantGroupName)
            .SendAsync("PendingChangeApproved", notification, cancellationToken);

        _logger.LogDebug(
            "PendingChangeApproved notification sent - Groups=[{GroupName}, {TenantGroupName}]",
            groupName, tenantGroupName);
    }

    public async Task NotifyPendingChangeRejectedAsync(
        PendingChangeRejectedNotification notification,
        CancellationToken cancellationToken = default)
    {
        var groupName = GetPendingChangeGroupName(notification.PendingChangeId);
        var tenantGroupName = GetTenantGroupName(notification.TenantId);

        _logger.LogInformation(
            "Sending PendingChangeRejected notification - PendingChangeId={PendingChangeId}, Reason={Reason}, RejectedBy={RejectedBy}",
            notification.PendingChangeId, notification.Reason, notification.RejectedBy);

        await _hubContext.Clients
            .Groups(groupName, tenantGroupName)
            .SendAsync("PendingChangeRejected", notification, cancellationToken);

        _logger.LogDebug(
            "PendingChangeRejected notification sent - Groups=[{GroupName}, {TenantGroupName}]",
            groupName, tenantGroupName);
    }

    public async Task NotifyPendingChangeAppliedAsync(
        PendingChangeAppliedNotification notification,
        CancellationToken cancellationToken = default)
    {
        var groupName = GetPendingChangeGroupName(notification.PendingChangeId);
        var tenantGroupName = GetTenantGroupName(notification.TenantId);

        _logger.LogInformation(
            "Sending PendingChangeApplied notification - PendingChangeId={PendingChangeId}, Result={Result}",
            notification.PendingChangeId, notification.Result);

        await _hubContext.Clients
            .Groups(groupName, tenantGroupName)
            .SendAsync("PendingChangeApplied", notification, cancellationToken);

        _logger.LogDebug(
            "PendingChangeApplied notification sent - Groups=[{GroupName}, {TenantGroupName}]",
            groupName, tenantGroupName);
    }

    public async Task NotifyPendingChangeExpiredAsync(
        PendingChangeExpiredNotification notification,
        CancellationToken cancellationToken = default)
    {
        var groupName = GetPendingChangeGroupName(notification.PendingChangeId);
        var tenantGroupName = GetTenantGroupName(notification.TenantId);

        _logger.LogInformation(
            "Sending PendingChangeExpired notification - PendingChangeId={PendingChangeId}, ExpiredAt={ExpiredAt}",
            notification.PendingChangeId, notification.ExpiredAt);

        await _hubContext.Clients
            .Groups(groupName, tenantGroupName)
            .SendAsync("PendingChangeExpired", notification, cancellationToken);

        _logger.LogDebug(
            "PendingChangeExpired notification sent - Groups=[{GroupName}, {TenantGroupName}]",
            groupName, tenantGroupName);
    }

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

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