using MediatR;
using ColaFlow.API.Services;
using ColaFlow.Modules.ProjectManagement.Domain.Events;
using Microsoft.Extensions.Logging;

namespace ColaFlow.API.EventHandlers;

/// <summary>
/// Handles Sprint domain events and sends SignalR notifications
/// </summary>
public class SprintEventHandlers(
    IRealtimeNotificationService notificationService,
    ILogger<SprintEventHandlers> logger,
    IHttpContextAccessor httpContextAccessor)
    :
        INotificationHandler<SprintCreatedEvent>,
        INotificationHandler<SprintUpdatedEvent>,
        INotificationHandler<SprintStartedEvent>,
        INotificationHandler<SprintCompletedEvent>,
        INotificationHandler<SprintDeletedEvent>
{
    private readonly IRealtimeNotificationService _notificationService = notificationService ?? throw new ArgumentNullException(nameof(notificationService));
    private readonly ILogger<SprintEventHandlers> _logger = logger ?? throw new ArgumentNullException(nameof(logger));
    private readonly IHttpContextAccessor _httpContextAccessor = httpContextAccessor ?? throw new ArgumentNullException(nameof(httpContextAccessor));

    public async Task Handle(SprintCreatedEvent notification, CancellationToken cancellationToken)
    {
        try
        {
            var tenantId = GetCurrentTenantId();
            await _notificationService.NotifySprintCreated(
                tenantId,
                notification.ProjectId,
                notification.SprintId,
                notification.SprintName
            );
            _logger.LogInformation("Sprint created notification sent: {SprintId}", notification.SprintId);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to send Sprint created notification: {SprintId}", notification.SprintId);
        }
    }

    public async Task Handle(SprintUpdatedEvent notification, CancellationToken cancellationToken)
    {
        try
        {
            var tenantId = GetCurrentTenantId();
            await _notificationService.NotifySprintUpdated(
                tenantId,
                notification.ProjectId,
                notification.SprintId,
                notification.SprintName
            );
            _logger.LogInformation("Sprint updated notification sent: {SprintId}", notification.SprintId);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to send Sprint updated notification: {SprintId}", notification.SprintId);
        }
    }

    public async Task Handle(SprintStartedEvent notification, CancellationToken cancellationToken)
    {
        try
        {
            var tenantId = GetCurrentTenantId();
            await _notificationService.NotifySprintStarted(
                tenantId,
                notification.ProjectId,
                notification.SprintId,
                notification.SprintName
            );
            _logger.LogInformation("Sprint started notification sent: {SprintId}", notification.SprintId);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to send Sprint started notification: {SprintId}", notification.SprintId);
        }
    }

    public async Task Handle(SprintCompletedEvent notification, CancellationToken cancellationToken)
    {
        try
        {
            var tenantId = GetCurrentTenantId();
            await _notificationService.NotifySprintCompleted(
                tenantId,
                notification.ProjectId,
                notification.SprintId,
                notification.SprintName
            );
            _logger.LogInformation("Sprint completed notification sent: {SprintId}", notification.SprintId);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to send Sprint completed notification: {SprintId}", notification.SprintId);
        }
    }

    public async Task Handle(SprintDeletedEvent notification, CancellationToken cancellationToken)
    {
        try
        {
            var tenantId = GetCurrentTenantId();
            await _notificationService.NotifySprintDeleted(
                tenantId,
                notification.ProjectId,
                notification.SprintId,
                notification.SprintName
            );
            _logger.LogInformation("Sprint deleted notification sent: {SprintId}", notification.SprintId);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to send Sprint deleted notification: {SprintId}", notification.SprintId);
        }
    }

    private Guid GetCurrentTenantId()
    {
        var tenantIdClaim = _httpContextAccessor?.HttpContext?.User
            .FindFirst("tenant_id")?.Value;

        if (Guid.TryParse(tenantIdClaim, out var tenantId) && tenantId != Guid.Empty)
        {
            return tenantId;
        }

        return Guid.Empty; // Default for non-HTTP contexts
    }
}
