using Inspectron.Epson.PrintServer.Printers.Utils.FinalRecipe;

namespace Inspectron.Epson.PrintServer.Printers.Utils.InvoiceReceipt;

public class ReceiptConverter
{
    private readonly int _lineWidth;
    private readonly int _bigFontLineWidth;

    public ReceiptConverter(int lineWidth = 42, int bigFontLineWidth = 21)
    {
        _lineWidth = lineWidth;
        _bigFontLineWidth = bigFontLineWidth;
    }

    public List<PrintCommand> ConvertToPrintCommands(InvoiceReceipt invoiceReceipt)
    {
        var commands = new List<PrintCommand>();

        // Header - Company info
        commands.Add(new PrintCommand(Center(invoiceReceipt.CompanyName, false)));
        commands.Add(new PrintCommand(Center(invoiceReceipt.Address1, false)));
        commands.Add(new PrintCommand(Center(invoiceReceipt.Address2, false)));
        commands.Add(new PrintCommand(Center(invoiceReceipt.Phone, false)));
        commands.Add(new PrintCommand(""));
        commands.Add(new PrintCommand(""));

        // InvoiceReceipt info
        string receiptLine = "";
        if (invoiceReceipt.ReceiptNumber != null)
            receiptLine += $"Rechnung Nr. {invoiceReceipt.ReceiptNumber}".PadRight(_lineWidth / 2);
        else
            receiptLine += $"".PadRight(_lineWidth / 2);
        receiptLine += $"{invoiceReceipt.DateTime:HH:mm dd.MM.yyyy}".PadLeft(_lineWidth / 2);

        commands.Add(new PrintCommand(receiptLine,isBold:true));
        
        if(invoiceReceipt.Guests != null)
            commands.Add(new PrintCommand($"Guests: {invoiceReceipt.Guests}"));
        
        commands.Add(new PrintCommand(""));

        // Items
        foreach (var item in invoiceReceipt.Items)
        {
            PrintItem(item, commands);
        }

        commands.Add(new PrintCommand(""));
        commands.Add(new PrintCommand("---------".PadLeft(_lineWidth)));
        commands.Add(new PrintCommand(""));

        // Total
        string totalLine = $"Summe:  {invoiceReceipt.Total:F2} {invoiceReceipt.Currency}";
        commands.Add(new PrintCommand(Center(totalLine, true), true, true));
        commands.Add(new PrintCommand(""));
        commands.Add(new PrintCommand(Center($"Tisch: {invoiceReceipt.TableNumber}",false), false));
        commands.Add(new PrintCommand(Center(invoiceReceipt.ThankYouMessage, false)));
        commands.Add(new PrintCommand(""));
        commands.Add(new PrintCommand(Center("Zwischenrechnung", false),isBold:true));

        return commands;
    }

    private void PrintItem(ReceiptItem item, List<PrintCommand> commands)
    {
        string quantityPrefix = $"{item.Quantity}x ";
        string prices = $"{item.UnitPrice:F2}" + $"{item.TotalPrice:F2}".PadLeft(7) + $" {item.TaxCategory}";
        string fullLine = quantityPrefix + item.Description;

        int spacesNeeded = _lineWidth - fullLine.Length - prices.Length;

        if (spacesNeeded >= 1 || string.IsNullOrEmpty(item.Description))
        {
            if (spacesNeeded < 1) spacesNeeded = 1;
            commands.Add(new PrintCommand(fullLine + new string(' ', spacesNeeded) + prices));
        }
        else
        {
            int descriptionAvailable = _lineWidth - quantityPrefix.Length - prices.Length - 1;

            if (descriptionAvailable <= 0)
            {
                commands.Add(new PrintCommand(fullLine));
            }
            else
            {
                var words = item.Description.Split(' ');
                var lines = new List<string>();
                string currentLine = "";

                foreach (var word in words)
                {
                    if (currentLine.Length == 0)
                    {
                        currentLine = word;
                    }
                    else if (currentLine.Length + 1 + word.Length <= descriptionAvailable)
                    {
                        currentLine += " " + word;
                    }
                    else
                    {
                        lines.Add(currentLine);
                        currentLine = word;
                    }
                }

                if (currentLine.Length > 0)
                {
                    lines.Add(currentLine);
                }

                // First line with prefix and right-aligned prices
                string firstLineText = quantityPrefix + lines[0];
                int firstSpaces = _lineWidth - firstLineText.Length - prices.Length;
                if (firstSpaces >= 1)
                {
                    commands.Add(new PrintCommand(firstLineText + new string(' ', firstSpaces) + prices));
                }
                else
                {
                    commands.Add(new PrintCommand(firstLineText));
                    commands.Add(new PrintCommand(prices.PadLeft(_lineWidth)));
                }

                // Continuation lines indented to align with description
                string continuationIndent = new string(' ', quantityPrefix.Length);
                for (int i = 1; i < lines.Count; i++)
                {
                    commands.Add(new PrintCommand(continuationIndent + lines[i]));
                }
            }
        }

        // SubItems
        if (item.SubItems != null)
        {
            foreach (var subItem in item.SubItems)
            {
                commands.Add(new PrintCommand($"  - {subItem}"));
            }
        }
    }

    private string Center(string text, bool isBigFont)
    {
        int effectiveLineWidth = isBigFont ? _bigFontLineWidth : _lineWidth;

        if (string.IsNullOrEmpty(text) || text.Length >= effectiveLineWidth)
            return text;

        int totalPadding = effectiveLineWidth - text.Length;
        int leftPadding = totalPadding / 2;

        return new string(' ', leftPadding) + text;
    }
}
