using Insight.Domain.Interfaces;
using Insight.Domain.Network;
using Insight.Domain.Network.Remote.Messages;
using Vaitr.Bus;
using Vaitr.Network;

namespace Insight.Web.Network.Remote.Handlers;

public class RemoteHandler : IMessageHandler<RemoteSession>
{
    private readonly Bus _bus;
    private readonly ISessionPool<RemoteSession, IMessage> _remotePool;
    private readonly ILogger<RemoteHandler> _logger;

    public RemoteHandler(Bus bus, ISessionPool<RemoteSession, IMessage> remotePool, ILogger<RemoteHandler> logger)
    {
        _bus = bus;
        _remotePool = remotePool;
        _logger = logger;
    }

    public async ValueTask HandleAsync<TMessage>(RemoteSession sender, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage
    {
        if (message is RemoteSessionRequest sessionRequest)
        {
            await OnSessionRequest(sender, sessionRequest, cancellationToken);
        }
        else if (message is CastRequestResponse castRequestResponse)
        {
            await OnCastRequestResponse(sender, castRequestResponse, cancellationToken);
        }
        else if (message is CastMetric metricData)
        {
            await OnMetricData(sender, metricData, cancellationToken);
        }
        else if (message is CastScreen screenData)
        {
            await OnScreenData(sender, screenData, cancellationToken);
        }
        else if (message is CastCursor cursorData)
        {
            await OnCursorData(sender, cursorData, cancellationToken);
        }
        else if (message is CastClipboardReceived clipboardData)
        {
            await OnClipboardData(sender, clipboardData, cancellationToken);
        }
        else if (message is CastAudio audioData)
        {
            await OnAudioData(sender, audioData, cancellationToken);
        }
    }

    private async Task OnSessionRequest(RemoteSession session, RemoteSessionRequest sessionRequest, CancellationToken cancellationToken)
    {
        _logger.LogInformation($"Remote {session.Id} => SessionRequest");

        session.Mode = sessionRequest.Mode;

        await session.SendAsync(new RemoteSessionResponse
        {
            SessionId = session.Id
        }, cancellationToken);
    }

    private async Task OnCastRequestResponse(RemoteSession session, CastRequestResponse castRequestResponse, CancellationToken cancellationToken)
    {
        _logger.LogInformation($"Remote {castRequestResponse.Id} => CastRequestResponse");

        await _bus.PublishAsync(castRequestResponse, cancellationToken);
    }

    private async Task OnMetricData(RemoteSession session, CastMetric streamMetrics, CancellationToken cancellationToken)
    {
        //_logger.LogInformation($"Remote {streamMetrics.Id} => MetricData");

        await _bus.PublishAsync(streamMetrics, cancellationToken);
    }

    private async Task OnScreenData(RemoteSession session, CastScreen screenData, CancellationToken cancellationToken)
    {
        //_logger.LogInformation($"Remote {screenData.Id} => ScreenData");

        await _bus.PublishAsync(screenData, cancellationToken);       
    }

    private async Task OnCursorData(RemoteSession session, CastCursor cursorChanged, CancellationToken cancellationToken)
    {
        //_logger.LogInformation($"Remote {cursorChanged.Id} => CursorData");

        await _bus.PublishAsync(cursorChanged, cancellationToken);
    }

    private async Task OnClipboardData(RemoteSession session, CastClipboardReceived clipboardChanged, CancellationToken cancellationToken)
    {
        _logger.LogInformation($"Remote {session.Id} => ClipboardData");

        await _bus.PublishAsync(clipboardChanged, cancellationToken);
    }

    private async Task OnAudioData(RemoteSession session, CastAudio audioSample, CancellationToken cancellationToken)
    {
        _logger.LogInformation($"Remote {session.Id} => AudioData");

        await _bus.PublishAsync(audioSample, cancellationToken);
    }
}