using System;
using System.IO;
using System.Threading.Tasks;
using Serilog;
using GeViScopeBridge.SDK;

namespace DiagnoseSetupClient
{
    class Program
    {
        static async Task Main(string[] args)
        {
            // Configure logging
            Log.Logger = new LoggerConfiguration()
                .MinimumLevel.Debug()
                .WriteTo.Console()
                .CreateLogger();

            try
            {
                Console.WriteLine("=== GeViSetupClient Diagnostic Tool ===\n");

                // Get connection details from command line or interactive
                string address, username, password;

                if (args.Length >= 3)
                {
                    // Command line mode: DiagnoseSetupClient.exe <address> <username> <password>
                    address = args[0];
                    username = args[1];
                    password = args[2];
                    Console.WriteLine($"Using command-line arguments:");
                    Console.WriteLine($"  Address: {address}");
                    Console.WriteLine($"  Username: {username}");
                    Console.WriteLine($"  Password: {new string('*', password.Length)}");
                }
                else
                {
                    // Interactive mode
                    Console.Write("GeViServer Address (default: localhost): ");
                    address = Console.ReadLine();
                    if (string.IsNullOrWhiteSpace(address))
                        address = "localhost";

                    Console.Write("Username (default: admin): ");
                    username = Console.ReadLine();
                    if (string.IsNullOrWhiteSpace(username))
                        username = "admin";

                    Console.Write("Password: ");
                    password = ReadPassword();
                }

                Console.WriteLine("\n\n1. Testing SetupClient Connection...");

                // Try with different aliasnames
                string[] aliasnamesToTry = { "", "localhost", "GeViServer", address };

                GeViSetupClientWrapper successfulClient = null;

                foreach (var aliasname in aliasnamesToTry)
                {
                    Console.WriteLine($"Trying with aliasname: '{aliasname}'");
                    var setupClient = new GeViSetupClientWrapper(address, username, password, aliasname);
                    bool connected = await setupClient.ConnectAsync();

                    if (connected)
                    {
                        Console.WriteLine($"✅ Connected successfully with aliasname: '{aliasname}'!\n");
                        successfulClient = setupClient;
                        break;
                    }
                    else
                    {
                        setupClient.Dispose();
                    }
                }

                if (successfulClient == null)
                {
                    Console.WriteLine("❌ Failed to connect with any aliasname");
                    return;
                }

                // Use the successfully connected client
                using (var setupClient = successfulClient)
                {

                    // Test ping
                    Console.WriteLine("2. Testing Ping...");
                    bool pingResult = setupClient.SendPing();
                    Console.WriteLine(pingResult ? "✅ Ping successful" : "❌ Ping failed");
                    Console.WriteLine();

                    // Read setup configuration
                    Console.WriteLine("3. Reading Setup Configuration...");
                    byte[] setupData = await setupClient.ReadSetupAsync();

                    Console.WriteLine($"✅ Read {setupData.Length} bytes of configuration\n");

                    // Save to file for inspection
                    string outputFile = Path.Combine(
                        Environment.CurrentDirectory,
                        $"setup_config_{DateTime.Now:yyyyMMdd_HHmmss}.dat"
                    );

                    File.WriteAllBytes(outputFile, setupData);
                    Console.WriteLine($"📁 Saved configuration to: {outputFile}\n");

                    // Analyze file format
                    Console.WriteLine("4. Analyzing File Format...");
                    AnalyzeSetupFile(setupData);

                    Console.WriteLine("\n5. Testing Write Setup (write back unchanged)...");

                    // In automated mode, skip write test by default
                    string response = "n";
                    if (args.Length < 3)
                    {
                        Console.Write("Write configuration back to server? (y/n): ");
                        response = Console.ReadLine();
                    }
                    else
                    {
                        Console.WriteLine("Skipping write test in automated mode (pass 4th argument 'y' to enable)");
                        if (args.Length >= 4 && args[3].ToLower() == "y")
                        {
                            response = "y";
                        }
                    }

                    if (response?.ToLower() == "y")
                    {
                        bool writeSuccess = await setupClient.WriteSetupAsync(setupData);
                        Console.WriteLine(writeSuccess
                            ? "✅ Configuration written successfully"
                            : "❌ Failed to write configuration");
                    }
                    else
                    {
                        Console.WriteLine("⏭️  Skipped write test");
                    }
                }

                Console.WriteLine("\n✅ All tests completed successfully!");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"\n❌ Error: {ex.Message}");
                Console.WriteLine($"Stack trace: {ex.StackTrace}");
            }
            finally
            {
                Log.CloseAndFlush();
            }

            // Only wait for key if in interactive mode (not automated)
            if (args.Length < 3)
            {
                Console.WriteLine("\nPress any key to exit...");
                try
                {
                    Console.ReadKey();
                }
                catch
                {
                    // Ignore if console input is redirected
                }
            }
        }

        static void AnalyzeSetupFile(byte[] data)
        {
            // Check if XML
            if (data.Length > 5)
            {
                string header = System.Text.Encoding.ASCII.GetString(data, 0, Math.Min(100, data.Length));

                if (header.StartsWith("<?xml") || header.StartsWith("<"))
                {
                    Console.WriteLine("  Format: XML");
                    Console.WriteLine($"  First 200 chars:\n{header}");
                    return;
                }
            }

            // Check for common text encodings
            try
            {
                string utf8Text = System.Text.Encoding.UTF8.GetString(data, 0, Math.Min(200, data.Length));
                if (IsText(utf8Text))
                {
                    Console.WriteLine("  Format: Text (UTF-8)");
                    Console.WriteLine($"  First 200 chars:\n{utf8Text}");
                    return;
                }
            }
            catch { }

            // Binary format
            Console.WriteLine("  Format: Binary");
            Console.WriteLine("  Hex dump (first 100 bytes):");
            HexDump(data, Math.Min(100, data.Length));
        }

        static bool IsText(string str)
        {
            foreach (char c in str)
            {
                if (char.IsControl(c) && c != '\r' && c != '\n' && c != '\t')
                    return false;
            }
            return true;
        }

        static void HexDump(byte[] data, int length)
        {
            for (int i = 0; i < length; i += 16)
            {
                Console.Write($"  {i:X4}: ");

                // Hex
                for (int j = 0; j < 16; j++)
                {
                    if (i + j < length)
                        Console.Write($"{data[i + j]:X2} ");
                    else
                        Console.Write("   ");
                }

                Console.Write(" ");

                // ASCII
                for (int j = 0; j < 16 && i + j < length; j++)
                {
                    byte b = data[i + j];
                    Console.Write(b >= 32 && b < 127 ? (char)b : '.');
                }

                Console.WriteLine();
            }
        }

        static string ReadPassword()
        {
            string password = "";
            ConsoleKeyInfo key;

            do
            {
                key = Console.ReadKey(true);

                if (key.Key == ConsoleKey.Backspace && password.Length > 0)
                {
                    password = password.Substring(0, password.Length - 1);
                    Console.Write("\b \b");
                }
                else if (key.Key != ConsoleKey.Enter && key.KeyChar != '\0')
                {
                    password += key.KeyChar;
                    Console.Write("*");
                }
            } while (key.Key != ConsoleKey.Enter);

            return password;
        }
    }
}
