#pragma warning disable IDE0130 // Namespace does not match folder structure
namespace ArmaDragonflyClient
#pragma warning restore IDE0130 // Namespace does not match folder structure
{
    internal class DragonflyDB
    {
        private readonly static DragonflyClient _client = new(Main.ADC_HOST, Main.ADC_PORT, Main.ADC_PASSWORD);
        private static CancellationTokenSource _listenerCts;

        public static async Task<string> DragonflyRaw(string key, string keyValue, string function = null)
        {
            await _client.ConnectAsync();
            await _client.SendCommandAsync($"SET {key} {keyValue}");
            string response = await _client.SendCommandAsync($"GET {key}");
            if (!string.IsNullOrEmpty(function))
                Main.Log($"ArmaDragonflyClient '{function}', '{response}'", "debug");
            return response;
        }

        public static async Task DragonflyGetAsync(string key, string function, string uniqueID, string entity = null, string call = "false", int bufferSize = Main.ADC_BUFFERSIZE)
        {
            if (string.IsNullOrEmpty(key) || string.IsNullOrEmpty(function))
            {
                Main.Log($"ArmaDragonflyClient 'key' or 'function' cannot be empty", "debug");
            }

            await _client.ConnectAsync();

            string data = await _client.SendCommandAsync($"GET {key}");

            Utils.CheckByteCount(uniqueID, data, function, entity, Convert.ToBoolean(call), bufferSize);
        }

        public static async Task DragonflySetAsync(string key, string keyValue)
        {
            await _client.ConnectAsync();
            await _client.SendCommandAsync($"SET {key} {keyValue}");
        }

        public static async Task DragonflyDeleteAsync(string key)
        {
            await _client.ConnectAsync();
            await _client.SendCommandAsync($"DEL {key}");
        }

        public static async Task DragonflyListAddAsync(string key, string keyValue)
        {
            await _client.ConnectAsync();
            await _client.SendCommandAsync($"RPUSH {key} {Utils.Base64Encode(keyValue)}");
        }

        public static async Task DragonflyListIndexAsync(string key, string keyIndex, string function, string uniqueID, string entity = null, string call = "false", int bufferSize = Main.ADC_BUFFERSIZE)
        {

            if (string.IsNullOrEmpty(key) || string.IsNullOrEmpty(keyIndex) || string.IsNullOrEmpty(function))
            {
                Main.Log($"ArmaDragonflyClient 'key', 'keyIndex' or 'function' cannot be empty", "debug");
            }

            await _client.ConnectAsync();

            string data = await _client.SendCommandAsync($"LINDEX {key} {keyIndex}", true);
            string decodedData = Utils.Base64Decode(data);

            Utils.CheckByteCount(uniqueID, decodedData, function, entity, Convert.ToBoolean(call), bufferSize);
        }

        public static async Task DragonflyListLengthAsync(string key, string function, string uniqueID, string entity = null, string call = "false", int bufferSize = Main.ADC_BUFFERSIZE)
        {
            if (string.IsNullOrEmpty(key) || string.IsNullOrEmpty(function))
            {
                Main.Log($"ArmaDragonflyClient 'key' or 'function' cannot be empty", "debug");
            }

            await _client.ConnectAsync();

            string data = await _client.SendCommandAsync($"LLEN {key}");

            Utils.CheckByteCount(uniqueID, data, function, entity, Convert.ToBoolean(call), bufferSize);
        }

        public static async Task DragonflyListRangeAsync(string key, string keyStart, string keyStop, string function, string uniqueID, string entity = null, string call = "false", int bufferSize = Main.ADC_BUFFERSIZE)
        {
            if (string.IsNullOrEmpty(key) || string.IsNullOrEmpty(keyStart) || string.IsNullOrEmpty(keyStop) || string.IsNullOrEmpty(function))
            {
                Main.Log($"ArmaDragonflyClient 'key', 'keyStart', 'keyStop' or 'function' cannot be empty", "debug");
            }

            await _client.ConnectAsync();

            string data = await _client.SendCommandAsync($"LRANGE {key} {keyStart} {keyStop}", true);

            Utils.CheckByteCount(uniqueID, data, function, entity, Convert.ToBoolean(call), bufferSize);
        }

        public static async Task DragonflyListRemoveAsync(string key, string keyIndex)
        {
            await _client.ConnectAsync();
            await _client.SendCommandAsync($"LSET {key} {keyIndex} DRAGONFLYREMOVE");
            await _client.SendCommandAsync($"LREM {key} 0 DRAGONFLYREMOVE");
        }

        public static async Task DragonflyListSetAsync(string key, string keyIndex, string keyValue)
        {
            await _client.ConnectAsync();
            await _client.SendCommandAsync($"LSET {key} {keyIndex} {Utils.Base64Encode(keyValue)}");
        }

        public static async Task DragonflyHashSetAsync(string key, string keyField, string keyValue)
        {
            await _client.ConnectAsync();
            await _client.SendCommandAsync($"HSET {key} {keyField} {keyValue}");
        }

        public static async Task DragonflyHashGetAsync(string key, string keyField, string function, string uniqueID, string entity = null, string call = "false", int bufferSize = Main.ADC_BUFFERSIZE)
        {
            if (string.IsNullOrEmpty(key) || string.IsNullOrEmpty(keyField) || string.IsNullOrEmpty(function))
            {
                Main.Log($"ArmaDragonflyClient 'key', 'keyField' or 'function' cannot be empty", "debug");
            }

            await _client.ConnectAsync();

            string data = await _client.SendCommandAsync($"HGET {key} {keyField}");

            Utils.CheckByteCount(uniqueID, data, function, entity, Convert.ToBoolean(call), bufferSize);
        }

        public static async Task DragonflyHashGetAllAsync(string key, string function, string uniqueID, string entity = null, string call = "false", int bufferSize = Main.ADC_BUFFERSIZE)
        {
            if (string.IsNullOrEmpty(key) || string.IsNullOrEmpty(function))
            {
                Main.Log($"ArmaDragonflyClient 'key' or 'function' cannot be empty", "debug");
            }

            await _client.ConnectAsync();

            string data = await _client.SendCommandAsync($"HGETALL {key}");

            Utils.CheckByteCount(uniqueID, data, function, entity, Convert.ToBoolean(call), bufferSize);
        }

        public static async Task DragonflyHashDeleteAsync(string key, string keyField)
        {
            await _client.ConnectAsync();
            await _client.SendCommandAsync($"HDEL {key} {keyField}");
        }

        public static async Task DragonflyFetchAsync(string key, string keyType, string function, string entity = null, string call = "false", int bufferSize = Main.ADC_BUFFERSIZE)
        {
            if (string.IsNullOrEmpty(key) || string.IsNullOrEmpty(keyType) || string.IsNullOrEmpty(function))
            {
                Main.Log($"ArmaDragonflyClient 'key', 'keyField' or 'function' cannot be empty", "debug");
            }

            await _client.ConnectAsync();

            string data = await _client.SendCommandAsync($"GET {key}");
            string uniqueId = Utils.GetUniqueId().ToString();

            Utils.CheckByteCount(uniqueId, data, function, entity, Convert.ToBoolean(call), bufferSize);
        }

        public static async Task DragonflySaveDBAsync()
        {
            await _client.ConnectAsync();
            string response = await _client.SendCommandAsync("SAVE");
            Main.Log($"ArmaDragonflyClient 'SAVE', Response: '{response}'", "debug");
        }

        public static async Task DragonflyPublishAsync(string channel, string message, string uniqueID)
        {
            await _client.ConnectAsync();
            await _client.SendCommandAsync($"PUBLISH {channel} {message}");
            Main.Log($"ArmaDragonflyClient 'PUBLISH', Channel: '{channel}', Message: '{message}'", "debug");
        }

        public static async Task DragonflySubscribeAsync(string channel, string eventType, string eventName, string uniqueID, string target = null, int bufferSize = Main.ADC_BUFFERSIZE)
        {
            await _client.ConnectAsync();

            try
            {
                await _client.SendCommandAsync($"SUBSCRIBE {channel}");
                Main.Log($"ArmaDragonflyClient 'SUBSCRIBE', Channel: '{channel}'", "debug");

                _listenerCts = new CancellationTokenSource();

                await Task.Run(async () =>
                {
                    await StartMessageListener(message => {
                        Utils.CheckByteCountPubSub(uniqueID, message, eventType, eventName, target, bufferSize);
                    });
                });
            }
            catch (Exception ex)
            {
                Main.Log($"ArmaDragonflyClient 'SUBSCRIBE', Exception: '{ex.Message}'", "error");
                throw;
            }
        }

        private static async Task StartMessageListener(Action<string> messageHandler)
        {
            try
            {
                while (!_listenerCts.Token.IsCancellationRequested)
                {
                    string response = await _client.ReceiveMessageAsync();

                    if (!string.IsNullOrEmpty(response))
                    {
                        var messageParts = response.Split(',');
                        if (messageParts.Length >= 3)
                        {
                            string messageType = messageParts[0];
                            string channel = messageParts[1];
                            string message = messageParts[2];

                            Main.Log($"ArmaDragonflyClient 'SUBSCRIBE', Channel: '{channel}', Message: '{message}'", "debug");
                            messageHandler(message);
                        }
                    }

                    await Task.Delay(10);
                }
            }
            catch (Exception ex)
            {
                Main.Log($"ArmaDragonflyClient 'SUBSCRIBE', Exception: '{ex.Message}'", "error");
                throw;
            }
        }

        public static void StopMessageListener()
        {
            _listenerCts.Cancel();
            _listenerCts.Dispose();
            _listenerCts = null;
        }
    }
}