using EonaCat.Json;
using System;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace EonaCat.Logger.Servers.Zabbix
{
    // 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.
    public class ZabbixRequest
    {
        private const int BUFFER_SIZE = 1024;

        /// <summary>
        /// The request to send to the Zabbix server
        /// </summary>
        public string Request { get; set; }

        /// <summary>
        /// The data to send to the Zabbix server
        /// </summary>
        public ZabbixData[] Data { get; set; }

        /// <summary>
        /// Zabbix request
        /// </summary>
        /// <param name="host"></param>
        /// <param name="key"></param>
        /// <param name="value"></param>
        public ZabbixRequest(string host, string key, string value)
        {
            Request = "sender data";
            Data = [new ZabbixData(host, key, value)];
        }

        /// <summary>
        /// Sends the request to the Zabbix server
        /// </summary>
        /// <param name="server"></param>
        /// <param name="port"></param>
        /// <param name="timeout"></param>
        /// <returns></returns>
        /// <exception cref="TimeoutException"></exception>
        public async Task<ZabbixResponse> SendAsync(string server, int port = 10051, int timeout = 500)
        {
            if (string.IsNullOrWhiteSpace(server))
            {
                return new ZabbixResponse();
            }

            string json = JsonHelper.ToJson(new ZabbixRequest(Data[0].Host, Data[0].Key, Data[0].Value));
            using (TcpClient tcpClient = new TcpClient(server, port))
            using (NetworkStream stream = tcpClient.GetStream())
            {
                byte[] header = Encoding.ASCII.GetBytes("ZBXD\x01");
                byte[] dataLength = BitConverter.GetBytes((long)json.Length);
                byte[] content = Encoding.ASCII.GetBytes(json);
                byte[] message = new byte[header.Length + dataLength.Length + content.Length];

                Buffer.BlockCopy(header, 0, message, 0, header.Length);
                Buffer.BlockCopy(dataLength, 0, message, header.Length, dataLength.Length);
                Buffer.BlockCopy(content, 0, message, header.Length + dataLength.Length, content.Length);

                stream.Write(message, 0, message.Length);
                stream.Flush();

                int counter = 0;
                while (!stream.DataAvailable)
                {
                    if (counter < timeout / 50)
                    {
                        counter++;
                        await Task.Delay(50).ConfigureAwait(false);
                    }
                    else
                    {
                        throw new TimeoutException();
                    }
                }

                byte[] responseBytes = new byte[BUFFER_SIZE];
                stream.Read(responseBytes, 0, responseBytes.Length);
                string responseAsString = Encoding.UTF8.GetString(responseBytes);
                string jsonResult = responseAsString.Substring(responseAsString.IndexOf('{'));
                return JsonHelper.ToObject<ZabbixResponse>(jsonResult);
            }
        }
    }
}