using Insight.Agent.Interfaces;
using Insight.Agent.Messages;
using Insight.Server.Network.Handlers.Agent;
using Microsoft.Extensions.Logging;
using System.Net.Sockets;
using Vaitr.Network;

namespace Insight.Server.Network;

public class AgentSession(AgentHandler agentHandler, IEnumerable<IAgentMessageHandler<AgentSession>> handlers, Socket socket, Stream stream, TcpConnectionOptions options, MemPackSerializer serializer, ILogger<AgentSession> logger)
    : TcpSession<MemPackSerializer, IAgentMessage>(socket, stream, options, serializer, logger)
{
    public string? Id { get; set; }

    private readonly AgentHandler _agentHandler = agentHandler;
    private readonly IEnumerable<IAgentMessageHandler<AgentSession>> _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(PacketContext<IAgentMessage> context, CancellationToken cancellationToken)
    {
        await _agentHandler.StatisticUpdateAsync(this, cancellationToken);
    }

    protected override async ValueTask OnReceivedAsync(PacketContext<IAgentMessage> context, CancellationToken cancellationToken)
    {
        if (Id is null && context.Data is not Authentication) return;

        await _agentHandler.StatisticUpdateAsync(this, cancellationToken);

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

                //await _mediator.Send(new AgentLog(new AgentLogEntity
                //{
                //    Category = CategoryEnum.Network.ToString(),
                //    Status = StatusEnum.Error.ToString(),
                //    Message = e.StackTrace
                //}, this), cancellationToken).ConfigureAwait(false);
            }
        }
    }

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

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