using System.Text;

#pragma warning disable IDE0130 // Namespace does not match folder structure
namespace FireflyClient
#pragma warning restore IDE0130 // Namespace does not match folder structure
{
    /// <summary>
    /// Command-line interface for Firefly
    /// </summary>
    public abstract class Program
    {
        private static async Task Main(string[] args)
        {
            Console.WriteLine("Firefly Client");
            Console.WriteLine("Enter commands (type EXIT to quit)");
            Console.WriteLine("Use double quotes for values with spaces: HSET email:1 subject \"Hello World\"");
            Console.WriteLine("Type HELP for basic commands or HELP EMAIL for email examples");

            // Parse command line arguments
            var host = "127.0.0.1";
            var port = 6379;
            var password = string.Empty;

            for (var i = 0; i < args.Length; i++)
            {
                switch (args[i])
                {
                    case "--host" or "-h" when i + 1 < args.Length:
                        host = args[++i];
                        break;
                    case "--port" or "-p" when i + 1 < args.Length && int.TryParse(args[i + 1], out var parsedPort):
                        port = parsedPort;
                        i++;
                        break;
                    case "--password" or "--pass" when i + 1 < args.Length:
                        password = args[++i];
                        break;
                    case "--help":
                    case "-?":
                        PrintClientHelp();
                        return;
                }
            }

            try
            {
                await RunInteractiveClientAsync(host, port, password);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Error: {ex.Message}");
            }
        }

        private static void PrintClientHelp()
        {
            Console.WriteLine("\nFirefly Client Usage:");
            Console.WriteLine("  --host, -h <hostname>    Server hostname or IP (default: 127.0.0.1)");
            Console.WriteLine("  --port, -p <port>        Server port (default: 6379)");
            Console.WriteLine("  --password, --pass <pwd> Server password");
            Console.WriteLine("  --help, -?               Show this help message\n");
            Console.WriteLine("Example: FireflyClient --host localhost --port 6380 --password secret123\n");
        }

        private static Task RunInteractiveClientAsync(string host, int port, string password)
        {
            using var client = new FireflyClient(host, port);
            Console.WriteLine($"Connecting to server at {host}:{port}...");
            Console.WriteLine("Connected to server!");

            // If password wasn't provided as a command line argument, prompt for it
            if (string.IsNullOrEmpty(password))
            {
                Console.Write("Enter password (leave empty if no password required): ");
                password = Console.ReadLine() ?? string.Empty;
            }

            // Authenticate if password was provided
            if (!string.IsNullOrEmpty(password))
            {
                var success = client.Authenticate(password);

                // Check if authentication failed
                if (!success)
                {
                    Console.WriteLine("Authentication failed. Disconnecting.");
                    return Task.CompletedTask;
                }
            }

            while (true)
            {
                // Get command from user
                Console.Write("> ");
                var input = Console.ReadLine() ?? string.Empty;

                if (string.IsNullOrEmpty(input) || input.Equals("EXIT", StringComparison.OrdinalIgnoreCase))
                {
                    // Send QUIT command before exiting
                    try
                    {
                        var response = client.ExecuteCommand("QUIT");
                        Console.WriteLine($"{response.TrimEnd('\r', '\n')}");
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine($"Error while quitting: {ex.Message}");
                    }
                    break;
                }

                // Check for help commands
                if (input.Equals("HELP", StringComparison.OrdinalIgnoreCase))
                {
                    PrintBasicCommands();
                    continue;
                }
                // Handle clear screen command
                else if (input.Equals("CLS", StringComparison.OrdinalIgnoreCase) || 
                         input.Equals("CLEAR", StringComparison.OrdinalIgnoreCase))
                {
                    Console.Clear();
                    continue;
                }

                try
                {
                    // Parse the command
                    var parts = SplitCommandLine(input);
                    if (parts.Length == 0) continue;

                    var command = parts[0];
                    string[] args = [.. parts.Skip(1)];

                    // Execute the command
                    var response = client.ExecuteCommand(command, args);
                    FormatAndPrintResponse(response);
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"Error: {ex.Message}");
                }
            }

            Console.WriteLine("Disconnected from server.");
            return Task.CompletedTask;
        }
        
        // Helper method to split command line respecting quotes
        private static string[] SplitCommandLine(string commandLine)
        {
            var result = new List<string>();
            var inQuotes = false;
            StringBuilder currentArg = new();
            
            foreach (var c in commandLine)
            {
                switch (c)
                {
                    case '"':
                        inQuotes = !inQuotes;
                        // Don't include the quote character
                        break;
                    case ' ' when !inQuotes:
                    {
                        // End of argument
                        if (currentArg.Length <= 0) continue;
                        result.Add(currentArg.ToString());
                        currentArg.Clear();
                        break;
                    }
                    default:
                        currentArg.Append(c);
                        break;
                }
            }
            
            // Add the last argument if any
            if (currentArg.Length > 0)
            {
                result.Add(currentArg.ToString());
            }
            
            return [.. result];
        }

        private static void FormatAndPrintResponse(string response)
        {
            // Remove trailing whitespace
            response = response.TrimEnd();
            
            if (response.StartsWith('*') && response.Contains("\r\n"))
            {
                // Format array responses for better readability
                var parts = response.Split("\r\n");
                if (parts.Length > 1)
                {
                    for (var i = 1; i < parts.Length; i++)
                    {
                        if (string.IsNullOrEmpty(parts[i])) continue;
                        // For simple string and bulk string responses in an array
                        if (parts[i].StartsWith('+') || parts[i].StartsWith('$'))
                        {
                            Console.WriteLine($"{i}) {parts[i][1..]}");
                        }
                        else if (!parts[i].StartsWith('*'))  // Skip the array count line
                        {
                            Console.WriteLine($"{i}) {parts[i]}");
                        }
                    }
                    return;
                }
            }
            
            // Default formatting
            Console.WriteLine($"{response}");
        }
        
        // Helper method: Print basic commands
        private static void PrintBasicCommands()
        {
            Console.WriteLine("\n==== Basic Firefly Commands ====");
            
            Console.WriteLine("\n## String Operations ##");
            Console.WriteLine("SET key value              # Set a string value");
            Console.WriteLine("GET key                    # Get a string value");
            Console.WriteLine("DEL key                    # Delete a key");
            Console.WriteLine("SEXISTS key                # Check if string key exists");
            
            Console.WriteLine("\n## List Operations ##");
            Console.WriteLine("LPUSH key value            # Add value to the beginning of a list");
            Console.WriteLine("RPUSH key value            # Add value to the end of a list");
            Console.WriteLine("LPOP key                   # Remove and return the first element");
            Console.WriteLine("RPOP key                   # Remove and return the last element");
            Console.WriteLine("LRANGE key start end       # Get a range of elements (0 -1 for all)");
            Console.WriteLine("LINDEX key index           # Get element at specific position");
            Console.WriteLine("LGET key [index]           # Get entire list or element at index");
            Console.WriteLine("LEXISTS key                # Check if list key exists");
            
            Console.WriteLine("\n## Hash Operations ##");
            Console.WriteLine("HSET key field value       # Set a field in a hash");
            Console.WriteLine("HGET key field             # Get a field from a hash");
            Console.WriteLine("HDEL key field             # Delete a field from a hash");
            Console.WriteLine("HEXISTS key field          # Check if field exists in hash");
            Console.WriteLine("HGETALL key                # Get all fields and values in a hash");
            Console.WriteLine("HMSET key field1 val1...   # Set multiple fields at once");
            Console.WriteLine("HASKEY key                 # Check if hash key exists");
            
            Console.WriteLine("\n## Server Operations ##");
            Console.WriteLine("PING                       # Test connection");
            Console.WriteLine("ECHO message               # Echo a message");
            Console.WriteLine("SAVE                       # Save database to disk");
            Console.WriteLine("BGSAVE                     # Save database in background");
            Console.WriteLine("QUIT                       # Gracefully disconnect from server");
            
            Console.WriteLine("\n## Help Commands ##");
            Console.WriteLine("HELP                       # Show this help message");
            Console.WriteLine("HELP EMAIL                 # Show email storage examples");
            Console.WriteLine("CLS, CLEAR                 # Clear the console screen");
            Console.WriteLine("EXIT                       # Exit the client");
        }
    }
}