using Insight.Domain.Interfaces;
using Insight.Domain.Network;
using Insight.Domain.Network.Agent.Messages;
using Insight.Server.Network.Agent.Handlers;
using Microsoft.Extensions.Logging;
using Vaitr.Network;

namespace Insight.Server.Network.Agent;

public class AgentSession : TcpSession<IMessage>
{
    public string? Id { get; set; }

    private readonly AgentHandler _agentHandler;
    private readonly IEnumerable<IMessageHandler<AgentSession>> _handlers;

    public AgentSession(AgentHandler agentHandler, IEnumerable<IMessageHandler<AgentSession>> handlers, ISerializer<IMessage> serializer, ILogger<AgentSession> logger) : base(serializer, logger)
    {
        _agentHandler = agentHandler;
        _handlers = handlers;
    }

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

        var request = new AuthenticationRequest();

        foreach (var handler in _handlers)
        {
            await handler.HandleAsync(this, request, cancellationToken);
        }

        await _agentHandler.ConnectedAsync(this, default);
        await _agentHandler.StatisticUpdateAsync(this, default);

        _logger.LogInformation("Agent ({ep?}) ID: {id}", RemoteEndPoint, Id);
    }

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

        await _agentHandler.StatisticUpdateAsync(this, default);
        await _agentHandler.DisconnectedAsync(this, default);
    }

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

        await _agentHandler.StatisticUpdateAsync(this, cancellationToken);
    }

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

        if (Id is null && context.Packet is not AuthenticationResponse) return;

        await _agentHandler.StatisticUpdateAsync(this, cancellationToken);

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

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

        await _agentHandler.StatisticUpdateAsync(this, cancellationToken);
    }
}