using System.Text;
using System.Text.RegularExpressions;

namespace Firefly
{
    public partial class Firefly
    {
        #region Utility Methods
        /// <summary>
        /// Splits a string respecting quoted sections.
        /// </summary>
        /// <param name="input">The input string to split</param>
        /// <returns>An array of tokens from the input string</returns>
        static string[] SplitRespectingQuotes(string input)
        {
            var result = new List<string>();
            bool inQuotes = false;
            StringBuilder currentToken = new();
            
            for (int i = 0; i < input.Length; i++)
            {
                char c = input[i];
                
                if (c == '"')
                {
                    // Toggle quote state
                    inQuotes = !inQuotes;
                }
                else if (c == ' ' && !inQuotes)
                {
                    // Space outside quotes - token boundary
                    if (currentToken.Length > 0)
                    {
                        // Add the completed token
                        string token = currentToken.ToString();
                        result.Add(token);
                        currentToken.Clear();
                    }
                    // Skip the space
                    continue;
                }
                
                // Add the character to the current token
                currentToken.Append(c);
            }
            
            // Add final token if any
            if (currentToken.Length > 0)
            {
                result.Add(currentToken.ToString());
            }
            
            return [.. result];
        }

        [GeneratedRegex(@"([^\s""]+)|""([^""]*)""")]
        private static partial Regex MyRegex();
        #endregion

        #region Sharding and Storage Helpers
        /// <summary>
        /// Creates an array of shards of type T.
        /// </summary>
        /// <typeparam name="T">The type of the shards</typeparam>
        /// <returns>An array of shards</returns>
        private static T[] CreateShards<T>() where T : new()
        {
            var shards = new T[ShardCount];
            for (int i = 0; i < ShardCount; i++)
            {
                shards[i] = new T();
            }
            return shards;
        }

        /// <summary>
        /// Creates an array of ReaderWriterLockSlim instances for list operations.
        /// </summary>
        /// <returns>An array of locks</returns>
        private static ReaderWriterLockSlim[] CreateListLocks()
        {
            var locks = new ReaderWriterLockSlim[ShardCount];
            for (int i = 0; i < ShardCount; i++)
            {
                locks[i] = new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion);
            }
            return locks;
        }

        /// <summary>
        /// Gets the shard index for a given key.
        /// </summary>
        /// <param name="key">The key to get the shard index for</param>
        /// <returns>The shard index</returns>
        private static int GetShardIndex(string key)
        {
            return key.GetHashCode() & 0x7FFFFFFF & ShardMask; // Ensure positive hash and fast modulo
        }
        #endregion

        #region Lock Helpers
        /// <summary>
        /// Creates an array of locks.
        /// </summary>
        /// <returns>An array of locks</returns>
        private static object[] CreateLocks()
        {
            var locks = new object[ShardCount];
            for (int i = 0; i < ShardCount; i++)
            {
                locks[i] = new object();
            }
            return locks;
        }
        #endregion

        #region Key Management Helpers
        /// <summary>
        /// Checks if a key exists in any store (string, list, or hash).
        /// </summary>
        /// <param name="key">The key to check</param>
        /// <returns>True if the key exists in any store, false otherwise</returns>
        private static bool KeyExistsInAnyStore(string key)
        {
            // Check string store
            if (StringStoreExists(key))
            {
                return true;
            }

            // Check list store
            if (ListStoreExists(key))
            {
                return true;
            }

            // Check hash store
            if (HashStoreExists(key))
            {
                return true;
            }

            return false;
        }

        /// <summary>
        /// Gets the type of a key if it exists in any store.
        /// </summary>
        /// <param name="key">The key to check</param>
        /// <returns>The type of the key ("string", "list", "hash", or null if not found)</returns>
        private static string? GetKeyType(string key)
        {
            // Check string store
            if (StringStoreExists(key))
            {
                return "string";
            }

            // Check list store
            if (ListStoreExists(key))
            {
                return "list";
            }

            // Check hash store
            if (HashStoreExists(key))
            {
                return "hash";
            }

            return null;
        }

        /// <summary>
        /// Ensures a key doesn't exist in any store before creating it in the target store.
        /// </summary>
        /// <param name="key">The key to check</param>
        /// <param name="targetType">The type of store where the key will be created</param>
        /// <returns>True if the key can be created, false if it already exists with a different type</returns>
        private static bool EnsureKeyDoesNotExist(string key, string targetType)
        {
            string? existingType = GetKeyType(key);
            if (existingType != null)
            {
                return false; // Key already exists with a different type
            }
            return true; // Key doesn't exist in any store
        }

        /// <summary>
        /// Handles the DEL command which removes a key from all stores (string, list, hash).
        /// </summary>
        /// <param name="key">The key to delete</param>
        /// <returns>The number of keys that were removed</returns>
        public static byte[] HandleDelCommand(string key)
        {
            if (string.IsNullOrEmpty(key))
            {
                return Encoding.UTF8.GetBytes("-ERR wrong number of arguments for 'del' command\r\n");
            }

            int deletedCount = 0;

            // Try to delete from string store
            if (StringStoreRemove(key))
            {
                deletedCount++;
            }

            // Try to delete from list store
            if (ListStoreRemove(key))
            {
                deletedCount++;
            }

            // Try to delete from hash store
            if (HashStoreRemove(key))
            {
                deletedCount++;
            }

            return Encoding.UTF8.GetBytes($":{deletedCount}\r\n");
        }

        /// <summary>
        /// Handles the TYPE command which returns the type of a key.
        /// </summary>
        /// <param name="key">The key to check the type of</param>
        /// <returns>The type of the key as a string response</returns>
        public static byte[] HandleTypeCommand(string key)
        {
            if (string.IsNullOrEmpty(key))
            {
                return Encoding.UTF8.GetBytes("-ERR wrong number of arguments for 'type' command\r\n");
            }

            // Check string store
            if (StringStoreExists(key))
            {
                return Encoding.UTF8.GetBytes("+string\r\n");
            }

            // Check list store
            if (ListStoreExists(key))
            {
                return Encoding.UTF8.GetBytes("+list\r\n");
            }

            // Check hash store
            if (HashStoreExists(key))
            {
                return Encoding.UTF8.GetBytes("+hash\r\n");
            }

            // Key doesn't exist
            return Encoding.UTF8.GetBytes("+none\r\n");
        }

        /// <summary>
        /// Handles the KEYS command which returns all keys matching a pattern.
        /// </summary>
        /// <param name="pattern">The pattern to match</param>
        /// <returns>A list of keys matching the pattern</returns>
        public static byte[] HandleKeysCommand(string pattern)
        {
            try
            {
                var matchingKeys = new List<string>();

                // Convert pattern to regex
                var regex = new Regex(
                    "^" + Regex.Escape(pattern).Replace("\\*", ".*").Replace("\\?", ".") + "$",
                    RegexOptions.Compiled
                );

                // Search in string store
                foreach (var shard in stringStoreShards)
                {
                    matchingKeys.AddRange(shard.Keys.Where(k => regex.IsMatch(k)));
                }

                // Search in list store
                foreach (var shard in listStoreShards)
                {
                    matchingKeys.AddRange(shard.Keys.Where(k => regex.IsMatch(k)));
                }

                // Search in hash store
                foreach (var shard in hashStoreShards)
                {
                    matchingKeys.AddRange(shard.Keys.Where(k => regex.IsMatch(k)));
                }

                // Sort keys for consistent results
                matchingKeys.Sort();

                // Return keys as newline-separated string
                string result = string.Join("\n", matchingKeys);
                return Encoding.UTF8.GetBytes($"+{result}\r\n");
            }
            catch (Exception ex)
            {
                return Encoding.UTF8.GetBytes($"-ERR error executing KEYS command: {ex.Message}\r\n");
            }
        }
        #endregion
    }
}