using Insight.Domain.Enums;
using Insight.Domain.Interfaces;
using Insight.Domain.Network;
using Insight.Domain.Network.Remote.Messages;
using Vaitr.Bus;
using Vaitr.Network;
using static Insight.Web.Messages.RemoteMessages;

namespace Insight.Web.Network.Remote;

public class RemoteSession : TcpSession<IMessage>
{
    public string Id { get; }
    public RemoteControlMode Mode { get; set; }

    private readonly Bus _bus;
    private readonly IEnumerable<IMessageHandler<RemoteSession>> _handlers;

    public RemoteSession(
        Bus bus,
        IEnumerable<IMessageHandler<RemoteSession>> handlers,
        ISerializer<IMessage> serializer,
        ILogger<RemoteSession> logger) : base(serializer, logger)
    {
        Id = GenerateRandomId();

        _bus = bus;
        _handlers = handlers;
    }

    protected override async ValueTask OnConnectedAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("Remote ({ep?}) connected", RemoteEndPoint);

        //return;

        await _bus.PublishAsync(new RemoteDisconnected(this), default);
    }

    protected override async ValueTask OnDisconnectedAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("Remote ({ep?}) disconnected", RemoteEndPoint);

        await _bus.PublishAsync(new RemoteDisconnected(this), default);
    }

    protected override async ValueTask OnSentAsync(IPacketContext<IMessage> context, CancellationToken cancellationToken)
    {
        //await base.OnSentAsync(context, cancellationToken);
    }

    protected override async ValueTask OnReceivedAsync(IPacketContext<IMessage> context, CancellationToken cancellationToken)
    {
        //await base.OnReceivedAsync(context, cancellationToken);

        foreach (var handler in _handlers)
        {
            try
            {
                await handler.HandleAsync(this, context.Packet, cancellationToken);
            }
            catch (Exception ex)
            {
                _logger.LogWarning("Remote ({ep?}) {ex}", RemoteEndPoint, ex.ToString());
            }
        }
    }

    protected override async ValueTask OnHeartbeatAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("Remote ({ep?}) Heartbeat", RemoteEndPoint);
    }

    public async Task ScreenDataAckAsync(CastScreen screenData, CancellationToken cancellationToken)
    {
        await SendAsync(new CastScreenReceived(screenData), cancellationToken);
    }

    private static string GenerateRandomId()
    {
        var random = new Random();
        string? sessionId = string.Empty;

        for (var i = 0; i < 3; i++) sessionId += random.Next(0, 999).ToString().PadLeft(3, '0');
        return sessionId;
    }
}