using System.Diagnostics;
using Inspectron.Epson;
using Inspectron.Epson.PrintServer.Printers.Utils;
using Inspectron.Epson.PrintServer.Printers.Utils.FinalRecipe;
using Inspectron.Epson.PrintServer.Printers.Utils.InvoiceReceipt;
using Inspectron.Epson.PrintServer.Printers.Utils.KitchenReceipt;
using Inspectron.Epson.PrintServer.Printers.Utils.OrderItems;

namespace EpsonTest;

public static class TestHelpers
{
    // Default connection settings
    public const string DefaultEpsonIp = "127.0.0.1";
    public const int DefaultEpsonPort = 8888;
    public const string DefaultHtmlPath = @".\test.html";
    public const int DefaultPaperWidth = 384;
    public const int KitchenPaperWidth = 258;

    #region Printer Creation

    public static async Task<EpsonPrinter> CreateEpsonPrinterAsync(
        string ip = DefaultEpsonIp,
        int port = DefaultEpsonPort, int paperWidth = DefaultPaperWidth)
    {
        var printer = new EpsonPrinter();
        await printer.ConnectAsync(ip, port);
        return printer;
    }

    public static async Task<HtmlPrinter> CreateHtmlPrinterAsync(
        string path = DefaultHtmlPath,
        int paperWidth = DefaultPaperWidth)
    {
        var printer = new HtmlPrinter(path, paperWidth: paperWidth);
        await printer.ConnectAsync("");
        return printer;
    }

    #endregion

    #region Receipt Builders

    public static FinalReceipt BuildSampleFinalReceipt(bool includeTax = true)
    {
        var receipt = new FinalReceipt
        {
            CompanyName = "Klingler Gastro AG",
            Address1 = "Münzplatz 3",
            Address2 = "CH-8001 Zürich",
            Phone = "043 321 22 22",
            ReceiptNumber = null,//"1-81-202",
            DateTime = new DateTime(2025, 12, 16, 14, 58, 0),
            Guests = 2,
            Total = 160.00m,
            Currency = "CHF",
            TotalInAlternateCurrency = 172.80m,
            AlternateCurrency = "EUR",
            PaymentMethod = "MASTER",
            PaymentAmount = 160.00m,
            WaiterName = "Yves",
            Terminal = "Hauptkasse ZH",
            TableNumber = "12",
            VatNumber = "CHE-449.635.880 MWST",
            ThankYouMessage = "Das Team bedankt sich herzlich für Ihren",
            GoodbyeMessageLine1 = "Besuch.",
            GoodbyeMessageLine2 = "Auf Wiedersehen.",
            IsDebtor = true,
            SplitPayments = new List<SplitPaymentInfo>
            {
                new() { PaymentMethod = "Cash", Amount = 50.00m, Currency = "CHF" },
                new() { PaymentMethod = "Card", Amount = 110.00m, Currency = "CHF" }
            },
            TerminalReceipts = new List<PaymentTerminalReceipt>
            {
                new()
                {
                    ReceiptType = "*** Kundenbeleg ***",
                    BookingType = "Buchung",
                    PaymentSystem = "TWINT",
                    TransactionNumber = "XXXXXXXXXXXXXXX1494",
                    TransactionDateTime = new DateTime(2025, 11, 11, 12, 34, 49),
                    TerminalId = "31108834",
                    AID = "A0000015749E",
                    TransactionSeqCount = "6127",
                    TransactionRefNo = "99036644599",
                    AuthCode = "0d3396",
                    AcquirerId = "2",
                    EftAmount = 67.00m,
                    TipAmount = 6.70m,
                    TotalEftAmount = 73.70m,
                    Currency = "CHF"
                },
                new()
                {
                    ReceiptType = "*** Kundenbeleg ***",
                    BookingType = "Buchung",
                    PaymentSystem = "MASTER",
                    TransactionNumber = "XXXXXXXXXXXXXXX2587",
                    TransactionDateTime = new DateTime(2025, 11, 11, 12, 36, 12),
                    TerminalId = "31108834",
                    AID = "A0000000041010",
                    TransactionSeqCount = "6128",
                    TransactionRefNo = "99036644600",
                    AuthCode = "1a4b2c",
                    AcquirerId = "1",
                    EftAmount = 93.00m,
                    TipAmount = 0.00m,
                    TotalEftAmount = 93.00m,
                    Currency = "CHF"
                }
            },
            DiscountInfo = new DiscountInfo()
            {
                Amount = -50.00m,
                Currency = "CHF",
                Description = "Fine Dine",

            }
        };

        // Add items
        receipt.Items.Add(new FinalReceiptItem
        {
            Quantity = 1,
            Description = "San Pellegrino 50cl",
            UnitPrice = 6.50m,
            TotalPrice = 6.50m,
            TaxCategory = "A"
        });

        receipt.Items.Add(new FinalReceiptItem
        {
            Quantity = 1,
            Description = "Panna 50cl",
            UnitPrice = 6.50m,
            TotalPrice = 6.50m,
            TaxCategory = "A"
        });

        receipt.Items.Add(new FinalReceiptItem
        {
            Quantity = 1,
            Description = "An item with really long description that should wrap",
            UnitPrice = 5.50m,
            TotalPrice = 5.50m,
            TaxCategory = "A"
        });

        receipt.Items.Add(new FinalReceiptItem
        {
            Quantity = 2,
            Description = "Business Lunch Menu Seco",
            UnitPrice = 44.00m,
            TotalPrice = 88.00m,
            TaxCategory = "A",
            SubItems = new List<string> { "Tomato Soup", "Grilled Salmon", "Tiramisu" }
        });

        receipt.Items.Add(new FinalReceiptItem
        {
            Quantity = 2,
            Description = "Brunello di Montalcino 1",
            UnitPrice = 16.00m,
            TotalPrice = 32.00m,
            TaxCategory = "A"
        });

        receipt.Items.Add(new FinalReceiptItem
        {
            Quantity = 2,
            Description = "Espresso",
            UnitPrice = 5.50m,
            TotalPrice = 11.00m,
            TaxCategory = "A"
        });

        receipt.Items.Add(new FinalReceiptItem
        {
            Quantity = 1,
            Description = "Tip",
            UnitPrice = 10.50m,
            TotalPrice = 10.50m,
            TaxCategory = "B"
        });

        if (includeTax)
        {
            // Add tax breakdown
            receipt.TaxBreakdown.Add(new TaxInfo
            {
                Category = "A",
                Rate = 8.1m,
                Gross = 149.50m,
                Net = 138.30m,
                TaxAmount = 11.20m,
                Currency = "CHF"
            });

            receipt.TaxBreakdown.Add(new TaxInfo
            {
                Category = "B",
                Rate = 0m,
                Gross = 10.50m,
                Net = 10.50m,
                TaxAmount = 0.00m,
                Currency = "CHF"
            });
        }

        return receipt;
    }

    public static InvoiceReceipt BuildSampleInvoiceReceipt()
    {
        var receipt = new InvoiceReceipt
        {
            CompanyName = "Klingler Gastro AG",
            Address1 = "Münzplatz 3",
            Address2 = "CH-8001 Zürich",
            Phone = "043 321 22 22",
            ReceiptNumber = null,//"1-81-202",
            DateTime = new DateTime(2025, 12, 16, 14, 58, 0),
            Guests = 2,
            Total = 160.00m,
            Currency = "CHF",
            TableNumber = "12",
            ThankYouMessage = "Thank you!"

        };

        // Add items
        receipt.Items.Add(new Inspectron.Epson.PrintServer.Printers.Utils.InvoiceReceipt.ReceiptItem
        {
            Quantity = 1,
            Description = "San Pellegrino 50cl",
            UnitPrice = 6.50m,
            TotalPrice = 6.50m,
            TaxCategory = "A"
        });

        receipt.Items.Add(new Inspectron.Epson.PrintServer.Printers.Utils.InvoiceReceipt.ReceiptItem
        {
            Quantity = 1,
            Description = "Panna 50cl",
            UnitPrice = 6.50m,
            TotalPrice = 6.50m,
            TaxCategory = "A"
        });

        receipt.Items.Add(new Inspectron.Epson.PrintServer.Printers.Utils.InvoiceReceipt.ReceiptItem
        {
            Quantity = 1,
            Description = "Granini Tomatensaft",
            UnitPrice = 5.50m,
            TotalPrice = 5.50m,
            TaxCategory = "A"
        });

        receipt.Items.Add(new Inspectron.Epson.PrintServer.Printers.Utils.InvoiceReceipt.ReceiptItem
        {
            Quantity = 2,
            Description = "Business Lunch Menu Seco",
            UnitPrice = 44.00m,
            TotalPrice = 88.00m,
            TaxCategory = "A",
            SubItems = new List<string> { "Tomato Soup", "Grilled Salmon", "Tiramisu" }
        });

        receipt.Items.Add(new Inspectron.Epson.PrintServer.Printers.Utils.InvoiceReceipt.ReceiptItem
        {
            Quantity = 2,
            Description = "Brunello di Montalcino 1",
            UnitPrice = 16.00m,
            TotalPrice = 32.00m,
            TaxCategory = "A"
        });

        receipt.Items.Add(new Inspectron.Epson.PrintServer.Printers.Utils.InvoiceReceipt.ReceiptItem
        {
            Quantity = 2,
            Description = "Espresso",
            UnitPrice = 5.50m,
            TotalPrice = 11.00m,
            TaxCategory = "A"
        });

        receipt.Items.Add(new Inspectron.Epson.PrintServer.Printers.Utils.InvoiceReceipt.ReceiptItem
        {
            Quantity = 1,
            Description = "Tip",
            UnitPrice = 10.50m,
            TotalPrice = 10.50m,
            TaxCategory = "B"
        });

        return receipt;
    }

    public static KitchenReceipt BuildSampleKitchenReceipt()
    {
        var receipt = new KitchenReceipt
        {
            Title = "Warme Küche",
            TransactionDateTime = new DateTime(2025, 10, 23, 12, 18, 0),
            ReceiptNumber = "132018166",
            WaiterName = "Mariano Amato",
            WaiterId = "32 (VK Restaurant)",
            TableNumber = "22"
        };

        receipt.Gangs.Add(new Gang(1, "Gang"));
        receipt.Gangs.Add(new Gang(2, "Gang"));

        receipt.Gangs[0].Dishes.Add(new Dish(1, "Avocado Sashimi")
        {
            Modifications = new DishModifications
            {
                Removed = new List<string> { "Wasabi" },
                Added = new List<string> { "Extra Ginger" }
            },
            Comment = "No soy sauce",
            GuestId = 1
        });
        receipt.Gangs[0].Dishes.Add(new Dish(1, "Baby Spinach Salad with Truffl"){GuestId = 2});
        //receipt.Gangs[0].Dishes.Add(new Dish(1, "Beef Tataki")
        //{
        //    Modifications = new DishModifications
        //    {
        //        Removed = new List<string> { "Onion" },
        //        Added = new List<string> { "Extra Sauce" }
        //    },
        //    Comment = "Medium rare",
        //    GuestId = 3
        //});
        //receipt.Gangs[0].Dishes.Add(new Dish(1, "Salmon Taco")
        //{
        //    Modifications = new DishModifications
        //    {
        //        Added = new List<string> { "Extra Lime" }
        //    },
        //    GuestId = 4
        //});

        receipt.Gangs[1].Dishes.Add(new Dish(1, "Avocado Sashimi") { GuestId = 1 });
        receipt.Gangs[1].Dishes.Add(new Dish(1, "Baby Spinach Salad with Truffl") { GuestId = 2 });
        //receipt.Gangs[1].Dishes.Add(new Dish(1, "Beef Tataki") { GuestId = 3 });
        //receipt.Gangs[1].Dishes.Add(new Dish(1, "Salmon Taco") { GuestId = 4 });

        return receipt;
    }

    public static KitchenReceipt BuildSampleKitchenReceiptNextDish()
    {
        var receipt = new KitchenReceipt
        {
            Title = "Warme Küche",
            TransactionDateTime = new DateTime(2025, 10, 23, 12, 18, 0),
            ReceiptNumber = "132018166",
            WaiterName = "Mariano Amato",
            WaiterId = "32 (VK Restaurant)",
            TableNumber = "22",
            SpecialInstruction = "Gang schicken"
        };

        receipt.Gangs.Add(new Gang(2, "Gang"));
        // to dishes in next dish
        //receipt.Gangs[0].Dishes.Add(new Dish(1, "Avocado Sashimi")
        //{
        //    Modifications = new DishModifications
        //    {
        //        Removed = new List<string> { "Wasabi" },
        //        Added = new List<string> { "Extra Ginger" }
        //    },
        //    Comment = "No soy sauce"
        //});
        //receipt.Gangs[0].Dishes.Add(new Dish(1, "Baby Spinach Salad with Truffl"));
        //receipt.Gangs[0].Dishes.Add(new Dish(1, "Beef Tataki")
        //{
        //    Modifications = new DishModifications
        //    {
        //        Removed = new List<string> { "Onion" },
        //        Added = new List<string> { "Extra Sauce" }
        //    },
        //    Comment = "Medium rare"
        //});
        //receipt.Gangs[0].Dishes.Add(new Dish(1, "Salmon Taco")
        //{
        //    Modifications = new DishModifications
        //    {
        //        Added = new List<string> { "Extra Lime" }
        //    }
        //});

        return receipt;
    }

    public static OrderItemsReceipt BuildSampleOrderItemsReceipt()
    {
        return new OrderItemsReceipt
        {
            OrderNumber = "1",
            QRInfo = "Margherita Pizza Classic longer text",
            DateTime = new DateTime(2026, 1, 14, 14, 35, 47),
            ClientNotes = "Some main note",
            Items = new List<OrderItem>
            {
                new()
                {
                    Number = 1,
                    Name = "pappara",
                    Quantity = 1,
                    SubItems = new List<string> { "pizza", "cola" },
                    Comment = "Cola zero please"
                },
                new()
                {
                    Number = 2,
                    Name = "Classic Beef Burger",
                    Quantity = 1,
                    Modifications = new ItemModifications
                    {
                        Removed = new List<string> { "Onion" },
                        Added = new List<string> { "butter" }
                    },
                    Comment = "Medium rare please"
                },
                new()
                {
                    Number = 3,
                    Name = "Margherita Pizza Classic",
                    Quantity = 2,
                    Size = "L"
                }
            }
        };
    }

    #endregion

    #region Print Helpers

    public static async Task PrintCommandsToHtmlPrinterAsync(
        HtmlPrinter printer,
        IEnumerable<PrintCommand> commands,
        string? logoPath = null,
        int logoWidth = 300,
        int logoXPosition = 42)
    {
        if (logoPath != null)
        {
            await printer.SetAbsolutePrintPosition(logoXPosition);
            await printer.LoadImageAsync(logoPath, logoWidth);
            await printer.PrintLoadedImage();
            await printer.SetAbsolutePrintPosition(0);
        }

        await printer.SetCustomLineSpacing(22);

        foreach (var command in commands)
        {
            if (command.IsBig)
                await printer.SetFontSizeAsync(2, 1);
            else
                await printer.SetFontSizeAsync(1, 1);

            await printer.SetEmphasized(command.IsBold);
            await printer.PrintTextAsync(command.Text + "\n");
        }
    }

    public static async Task PrintCommandsToEpsonPrinterAsync(
        EpsonPrinter printer,
        IEnumerable<PrintCommand> commands,
        bool useDelay = true,
        int delayMs = 200)
    {
        await printer.FeedLinesAsync(1);
        await printer.SetCustomLineSpacing(22);

        foreach (var command in commands)
        {
            if (command.IsCut)
            {
                await printer.FeedLinesAsync(10);
                if (useDelay) await Task.Delay(delayMs * 5);
                await printer.CutAsync(false);
                if (useDelay) await Task.Delay(delayMs);
                continue;

            }

            await printer.SetBiggerFontTM220(command.IsBig, command.IsTall | command.IsBig, secondaryFont: false);
            if (useDelay) await Task.Delay(delayMs);

            await printer.SetRedColor(command.IsRed);
            if (useDelay) await Task.Delay(delayMs);

            await printer.SetEmphasized(command.IsBold);
            if (useDelay) await Task.Delay(delayMs);

            await printer.PrintTextAsync(command.Text + "\n");
            if (useDelay) await Task.Delay(delayMs);
        }

        await printer.FeedLinesAsync(10);
        if (useDelay) await Task.Delay(delayMs * 5);
        await printer.CutAsync();
    }

    public static async Task PrintKitchenCommandsToHtmlPrinterAsync(
        HtmlPrinter printer,
        IEnumerable<PrintCommand> commands)
    {
        await printer.FeedLinesAsync(1);
        await printer.SetCustomLineSpacing(22);

        foreach (var command in commands)
        {
            if (command.IsCut)
            {
                await printer.CutAsync(false);
                continue;
            }
            if (command.IsBig)
                await printer.SetFontSizeAsync(2, 1);
            else
                await printer.SetFontSizeAsync(1, 1);

            await printer.SetRedColor(command.IsRed);
            await printer.SetEmphasized(command.IsBold);
            await printer.PrintTextAsync(command.Text + "\n");
        }
    }

    #endregion

    #region Console Output

    public static void PrintCommandsToConsole(IEnumerable<PrintCommand> commands)
    {
        Console.WriteLine("=== PRINT COMMANDS ===\n");
        foreach (var command in commands)
        {
            string attributes = "";
            if (command.IsBig) attributes += "[BIG] ";
            if (command.IsBold) attributes += "[BOLD] ";
            if (command.IsRed) attributes += "[RED] ";

            Console.WriteLine($"{attributes}{command.Text}");
        }
    }

    #endregion
}
