using EpsonTest;
using Inspectron.Epson.PrintServer.Printers.Utils.BarReceipt;
using Inspectron.Epson.PrintServer.Printers.Utils.FinalReceipt;
using Inspectron.Epson.PrintServer.Printers.Utils.InvoiceReceipt;
using Inspectron.Epson.PrintServer.Printers.Utils.KitchenReceipt;
using Inspectron.Epson.PrintServer.Printers.Utils.MoneyReturnReceipt;
using Inspectron.Epson.PrintServer.Printers.Utils.OrderItems;
using System.Text.Json;

// Non-interactive mode: `dotnet run -- <receiptType> [html|epson]`
// receiptType: kitchen | final | invoice | bar | orderitems | moneyreturn (or 0-5)
if (args.Length > 0)
{
    int rt = ParseReceiptTypeArg(args[0]);
    if (rt < 0)
    {
        Console.WriteLine($"Unknown receipt type: {args[0]}");
        return;
    }

    int pt = args.Length > 1 && args[1].Equals("epson", StringComparison.OrdinalIgnoreCase) ? 1 : 0;
    Console.WriteLine($"Running {GetReceiptTypeName(rt)} on {(pt == 0 ? "HTML" : "Epson")} printer...\n");
    await RunTest(rt, pt);
    Console.WriteLine("\nDone.");
    return;
}

while (true)
{
    Console.Clear();
    Console.WriteLine("=== Epson Print Test Runner ===\n");

    var receiptType = ShowMenu("Select receipt type:", new[]
    {
        "KitchenReceipt",
        "FinalReceipt",
        "InvoiceReceipt",
        "BarReceipt",
        "OrderItems",
        "MoneyReturnReceipt",
        "Exit"
    });

    if (receiptType == 6) break;

    var printerTarget = ShowMenu("Select printer target:", new[]
    {
        "HTML Printer (local file)",
        "Epson Printer (real hardware)"
    });

    Console.Clear();
    Console.WriteLine($"Running {GetReceiptTypeName(receiptType)} on {(printerTarget == 0 ? "HTML" : "Epson")} printer...\n");

    try
    {
        await RunTest(receiptType, printerTarget);
        Console.WriteLine("\nDone! Press any key to return to menu...");
    }
    catch (Exception ex)
    {
        Console.WriteLine($"\nError: {ex.Message}");
        Console.WriteLine("Press any key to return to menu...");
    }

    Console.ReadKey(true);
}

static int ShowMenu(string prompt, string[] options)
{
    int selected = 0;

    while (true)
    {
        Console.Clear();
        Console.WriteLine("=== Epson Print Test Runner ===\n");
        Console.WriteLine(prompt);
        Console.WriteLine();

        for (int i = 0; i < options.Length; i++)
        {
            if (i == selected)
            {
                Console.BackgroundColor = ConsoleColor.White;
                Console.ForegroundColor = ConsoleColor.Black;
                Console.WriteLine($"  > {options[i]}");
                Console.ResetColor();
            }
            else
            {
                Console.WriteLine($"    {options[i]}");
            }
        }

        Console.WriteLine("\n[Up/Down] Navigate   [Enter] Select");

        var key = Console.ReadKey(true).Key;
        switch (key)
        {
            case ConsoleKey.UpArrow:
                selected = (selected - 1 + options.Length) % options.Length;
                break;
            case ConsoleKey.DownArrow:
                selected = (selected + 1) % options.Length;
                break;
            case ConsoleKey.Enter:
                return selected;
        }
    }
}

static string GetReceiptTypeName(int index) => index switch
{
    0 => "KitchenReceipt",
    1 => "FinalReceipt",
    2 => "InvoiceReceipt",
    3 => "BarReceipt",
    4 => "OrderItems",
    5 => "MoneyReturnReceipt",
    _ => "Unknown"
};

static int ParseReceiptTypeArg(string arg) => arg.ToLowerInvariant() switch
{
    "0" or "kitchen" or "kitchenreceipt" => 0,
    "1" or "final" or "finalreceipt" => 1,
    "2" or "invoice" or "invoicereceipt" => 2,
    "3" or "bar" or "barreceipt" => 3,
    "4" or "orderitems" => 4,
    "5" or "moneyreturn" or "moneyreturnreceipt" or "refund" or "creditnote" => 5,
    _ => -1
};

static async Task RunTest(int receiptType, int printerTarget)
{
    switch (receiptType)
    {
        case 0: await RunKitchenReceiptTest(printerTarget); break;
        case 1: await RunFinalReceiptTest(printerTarget); break;
        case 2: await RunInvoiceReceiptTest(printerTarget); break;
        case 3: await RunBarReceiptTest(printerTarget); break;
        case 4: await RunOrderItemsTest(printerTarget); break;
        case 5: await RunMoneyReturnReceiptTest(printerTarget); break;
    }
}

static async Task RunKitchenReceiptTest(int printerTarget)
{
    var receipt = TestHelpers.BuildSampleKitchenReceipt();
    var serializedReceipt = JsonSerializer.Serialize(receipt, new JsonSerializerOptions { WriteIndented = true });
    var deserializedReceipt = JsonSerializer.Deserialize<KitchenReceipt>(serializedReceipt);

    var converter = new KitchenReceiptConverterKlinglers(bigLineWidth: 20, lineWidth: 33);
    var printCommands = converter.ConvertToPrintCommands(deserializedReceipt);

    TestHelpers.PrintCommandsToConsole(printCommands);

    if (printerTarget == 0)
    {
        var printer = await TestHelpers.CreateHtmlPrinterAsync(
            path: @".\kitchen_test.html",
            paperWidth: TestHelpers.KitchenPaperWidth);
        await TestHelpers.PrintKitchenCommandsToHtmlPrinterAsync(printer, printCommands);
        Console.WriteLine("Output written to: kitchen_test.html");
    }
    else
    {
        var printer = await TestHelpers.CreateEpsonPrinterAsync(paperWidth: TestHelpers.KitchenPaperWidth);
        await TestHelpers.PrintCommandsToEpsonPrinterAsync(printer, printCommands, useDelay: true);
    }
}

static async Task RunFinalReceiptTest(int printerTarget)
{
    var receipt = TestHelpers.BuildSampleFinalReceipt();
    var serializedReceipt = JsonSerializer.Serialize(receipt, new JsonSerializerOptions { WriteIndented = true });

    var converter = new FinalReceiptConverter(lineWidth: 48, bigFontLineWidth: 24);
    var printCommands = converter.Convert(serializedReceipt);

    TestHelpers.PrintCommandsToConsole(printCommands);

    if (printerTarget == 0)
    {
        var printer = await TestHelpers.CreateHtmlPrinterAsync();
        await TestHelpers.PrintCommandsToHtmlPrinterAsync(
            printer,
            printCommands,
            logoPath: "ristorante-klinglers.ch-logo_white_bg.png");
        Console.WriteLine("Output written to: test.html");
    }
    else
    {
        var printer = await TestHelpers.CreateEpsonPrinterAsync();
        await TestHelpers.PrintCommandsToEpsonPrinterAsync(printer, printCommands);
    }
}

static async Task RunInvoiceReceiptTest(int printerTarget)
{
    var receipt = TestHelpers.BuildSampleInvoiceReceipt();
    var serializedReceipt = JsonSerializer.Serialize(receipt, new JsonSerializerOptions { WriteIndented = true });

    var converter = new InvoiceReceiptConverter(lineWidth: 48, bigFontLineWidth: 24);
    var printCommands = converter.Convert(serializedReceipt);

    TestHelpers.PrintCommandsToConsole(printCommands);

    if (printerTarget == 0)
    {
        var printer = await TestHelpers.CreateHtmlPrinterAsync(path: @".\invoice_test.html");
        await TestHelpers.PrintCommandsToHtmlPrinterAsync(
            printer,
            printCommands,
            logoPath: "ristorante-klinglers.ch-logo_white_bg.png");
        Console.WriteLine("Output written to: invoice_test.html");
    }
    else
    {
        var printer = await TestHelpers.CreateEpsonPrinterAsync();
        await TestHelpers.PrintCommandsToEpsonPrinterAsync(printer, printCommands);
    }
}

static async Task RunBarReceiptTest(int printerTarget)
{
    var receipt = TestHelpers.BuildSampleBarReceipt();

    var converter = new BarReceiptConverter(lineWidth: 42, bigLineWidth: 22);
    var printCommands = converter.ConvertToPrintCommands(receipt);

    TestHelpers.PrintCommandsToConsole(printCommands);

    if (printerTarget == 0)
    {
        var printer = await TestHelpers.CreateHtmlPrinterAsync(
            path: @".\bar_test.html",
            paperWidth: TestHelpers.KitchenPaperWidth);
        await TestHelpers.PrintKitchenCommandsToHtmlPrinterAsync(printer, printCommands);
        Console.WriteLine("Output written to: bar_test.html");
    }
    else
    {
        var printer = await TestHelpers.CreateEpsonPrinterAsync(paperWidth: TestHelpers.KitchenPaperWidth);
        await TestHelpers.PrintCommandsToEpsonPrinterAsync(printer, printCommands, useDelay: true);
    }
}

static async Task RunOrderItemsTest(int printerTarget)
{
    var receipt = TestHelpers.BuildSampleOrderItemsReceipt();
    var serializedReceipt = JsonSerializer.Serialize(receipt, new JsonSerializerOptions { WriteIndented = true });

    var converter = new OrderItemsReceiptConverter(lineWidth: 50, bigFontLineWidth: 21);
    var printCommands = converter.Convert(serializedReceipt);

    TestHelpers.PrintCommandsToConsole(printCommands);

    if (printerTarget == 0)
    {
        var printer = await TestHelpers.CreateHtmlPrinterAsync(path: @".\order_items.html");
        await TestHelpers.PrintCommandsToHtmlPrinterAsync(printer, printCommands);
        Console.WriteLine("Output written to: order_items.html");
    }
    else
    {
        var printer = await TestHelpers.CreateEpsonPrinterAsync();
        await TestHelpers.PrintCommandsToEpsonPrinterAsync(printer, printCommands);
    }
}

static async Task RunMoneyReturnReceiptTest(int printerTarget)
{
    var receipt = TestHelpers.BuildSampleMoneyReturnReceipt();
    var serializedReceipt = JsonSerializer.Serialize(receipt, new JsonSerializerOptions { WriteIndented = true });

    var converter = new MoneyReturnReceiptConverter(lineWidth: 48, bigFontLineWidth: 24);
    var printCommands = converter.Convert(serializedReceipt);

    TestHelpers.PrintCommandsToConsole(printCommands);

    if (printerTarget == 0)
    {
        var printer = await TestHelpers.CreateHtmlPrinterAsync(path: @".\money_return_test.html");
        await TestHelpers.PrintCommandsToHtmlPrinterAsync(
            printer,
            printCommands,
            logoPath: "ristorante-klinglers.ch-logo_white_bg.png");
        Console.WriteLine("Output written to: money_return_test.html");
    }
    else
    {
        var printer = await TestHelpers.CreateEpsonPrinterAsync();
        await TestHelpers.PrintCommandsToEpsonPrinterAsync(printer, printCommands);
    }
}
