using EonaCat.LogStack.Core;
using System;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace EonaCat.LogStack.Flows
{
    public class SnmpTrapFlow : FlowBase
    {
        private readonly string _host;
        private readonly int _port;
        private readonly string _oid;
        private readonly UdpClient _udpClient;

        public SnmpTrapFlow(string host, int port = 162, string oid = "1.3.6.1.4.1.99999.1337.1.1.1", LogLevel minimumLevel = LogLevel.Trace) : base($"SNMP:{host}:{port}", minimumLevel)
        {
            _host = host ?? throw new ArgumentNullException(nameof(host));
            _port = port;
            _oid = oid;
            _udpClient = new UdpClient();
        }

        public override Task<WriteResult> BlastAsync(LogEvent logEvent, CancellationToken cancellationToken = default)
        {
            if (!IsEnabled || !IsLogLevelEnabled(logEvent))
            {
                return Task.FromResult(WriteResult.LevelFiltered);
            }

            var snmpTrapMessage = FormatSnmpTrapMessage(logEvent);
            var data = Encoding.ASCII.GetBytes(snmpTrapMessage);

            try
            {
                _udpClient.Send(data, data.Length, _host, _port);
                return Task.FromResult(WriteResult.Success);
            }
            catch
            {
                Interlocked.Increment(ref DroppedCount);
                return Task.FromResult(WriteResult.Dropped);
            }
        }

        private string FormatSnmpTrapMessage(LogEvent logEvent)
        {
            var stringBuilder = new StringBuilder();
            stringBuilder.Append($"Trap OID: {_oid}");
            stringBuilder.Append(" Timestamp: ").Append(logEvent.Timestamp);
            stringBuilder.Append(" Level: ").Append(logEvent.Level);
            stringBuilder.Append(" Message: ").Append(logEvent.Message);
            return stringBuilder.ToString();
        }

        public override Task FlushAsync(CancellationToken cancellationToken = default)
        {
            // SNMP traps are sent immediately, so no flushing needed.
            return Task.CompletedTask;
        }

        public override ValueTask DisposeAsync()
        {
            _udpClient?.Dispose();
            return base.DisposeAsync();
        }
    }
}
