using System;
using System.Collections.Generic;
using System.Net.Sockets;

namespace EonaCat.Logger.Servers.GrayLog;
// This file is part of the EonaCat project(s) which is released under the Apache License.
// See the LICENSE file or go to https://EonaCat.com/License for full license details.

/// <summary>
///   GrayLog client
/// </summary>
public class Graylog : IDisposable
{
    internal readonly object SendLock = new();
    private string _Hostname = "127.0.0.1";
    private int _Port = 12201;
    internal UdpClient Udp;

    public bool SupportsTcp { get; set; }
    public string Nickname { get; set; }
    public string IpPort => _Hostname + ":" + _Port;

    public Graylog() { }

    /// <summary>
    /// Graylog server
    /// </summary>
    /// <param name="hostname"></param>
    /// <param name="port"></param>
    /// <param name="nickName"></param>
    /// <param name="logType"></param>
    /// <exception cref="ArgumentNullException"></exception>
    /// <exception cref="ArgumentException"></exception>
    public Graylog(string hostname = "127.0.0.1", int port = 12201, string nickName = null, List<ELogType> typesToLog = null)
    {
        _Hostname = hostname ?? throw new ArgumentNullException(nameof(hostname));
        _Port = port >= 0 ? port : throw new ArgumentException("Port must be zero or greater.");
        TypesToLog = typesToLog;

        Nickname = nickName ?? IpPort;
        SetUdp();
    }

    public string Hostname
    {
        get => _Hostname;
        set
        {
            if (string.IsNullOrEmpty(value))
                throw new ArgumentNullException(nameof(Hostname));

            _Hostname = value;
            SetUdp();
        }
    }

    public int Port
    {
        get => _Port;
        set
        {
            if (value < 0)
                throw new ArgumentException("Port must be zero or greater.");

            _Port = value;
            SetUdp();
        }
    }

    public List<ELogType> TypesToLog { get; set; }
    public bool IsConnected { get; set; }

    internal void SetUdp()
    {
        try
        {
            DisposeUdp();
            Udp = new UdpClient(_Hostname, _Port);
            IsConnected = true;
        }
        catch
        {
            IsConnected = false;
        }
    }

    internal void DisposeUdp()
    {
        if (Udp != null)
        {
            IsConnected = false;

            try
            {
                Udp?.Close();
                Udp.Dispose();
            }
            catch 
            { 
                // Do nothing
            }
            Udp = null;
        }
    }

    public void Dispose()
    {
        DisposeUdp();
        GC.SuppressFinalize(this);
    }

    ~Graylog()
    {
        Dispose();
    }
}