using Inspectron.Epson.PrintServer.Printers.Utils;
using Inspectron.Epson.PrintServer.Printers.Utils.KitchenReceipt;
using System.Text.Json;

namespace Inspectron.Epson.TemplateEngine.Tests;

public class KitchenReceiptTemplateTests
{
    private const int LineWidth = 42;
    private const int BigLineWidth = 22;

    private readonly ReceiptTemplateEngine _engine = new();

    private static string GetTemplatePath()
    {
        return Path.Combine(AppContext.BaseDirectory, "Templates", "KitchenReceipt.xml");
    }

    [Fact]
    public void RenderKitchenReceipt_BasicStructure()
    {
        var template = File.ReadAllText(GetTemplatePath());

        var json = """
            {
              "Title": "Test Restaurant",
              "TransactionDateTime": "2024-03-15T14:30:00Z",
              "ReceiptNumber": "42",
              "WaiterName": "Max",
              "TableNumber": "5",
              "SpecialInstruction": null,
              "HasGangs": false,
              "HasDishes": false,
              "Gangs": [],
              "Dishes": []
            }
            """;

        var commands = _engine.Render(template, json, LineWidth, BigLineWidth);

        Assert.True(commands.Count > 0);

        // First line: title centered in big font, red
        Assert.True(commands[0].IsBig);
        Assert.True(commands[0].IsTall);
        Assert.True(commands[0].IsRed);
        Assert.Contains("Test Restaurant", commands[0].Text);

        // Second line: separator
        Assert.Equal(new string('-', LineWidth), commands[1].Text);

        // Empty line
        Assert.Equal("", commands[2].Text);
    }

    [Fact]
    public void RenderKitchenReceipt_WithSpecialInstruction()
    {
        var template = File.ReadAllText(GetTemplatePath());

        var json = """
            {
              "Title": "Test Restaurant",
              "TransactionDateTime": "2024-03-15T14:30:00Z",
              "ReceiptNumber": "42",
              "WaiterName": "Max",
              "TableNumber": "5",
              "SpecialInstruction": "RUSH ORDER",
              "HasGangs": false,
              "HasDishes": false,
              "Gangs": [],
              "Dishes": []
            }
            """;

        var commands = _engine.Render(template, json, LineWidth, BigLineWidth);

        // Should contain the special instruction
        var specialCommands = commands.Where(c => c.Text.Contains("RUSH ORDER")).ToList();
        Assert.NotEmpty(specialCommands);
        Assert.True(specialCommands[0].IsBig);
        Assert.True(specialCommands[0].IsBold);
    }

    [Fact]
    public void RenderKitchenReceipt_WithGangs()
    {
        var template = File.ReadAllText(GetTemplatePath());

        var json = """
            {
              "Title": "Test Restaurant",
              "TransactionDateTime": "2024-03-15T14:30:00Z",
              "ReceiptNumber": "42",
              "WaiterName": "Max",
              "TableNumber": "5",
              "SpecialInstruction": null,
              "HasGangs": true,
              "HasDishes": false,
              "Gangs": [
                {
                  "Id": 1,
                  "Name": "Vorspeise",
                  "Dishes": [
                    {
                      "Number": 2,
                      "Name": "Caesar Salad",
                      "GuestPrefix": "",
                      "GuestId": null,
                      "Modifications": { "Removed": [], "Added": [], "HasModifications": false },
                      "Comment": null
                    }
                  ]
                },
                {
                  "Id": 2,
                  "Name": "Hauptgang",
                  "Dishes": [
                    {
                      "Number": 1,
                      "Name": "Wiener Schnitzel",
                      "GuestPrefix": "",
                      "GuestId": null,
                      "Modifications": { "Removed": ["Pommes"], "Added": ["Reis"], "HasModifications": true },
                      "Comment": "Well done"
                    }
                  ]
                }
              ],
              "Dishes": []
            }
            """;

        var commands = _engine.Render(template, json, LineWidth, BigLineWidth);

        // Should contain gang names
        Assert.Contains(commands, c => c.Text.Contains("1. Vorspeise"));
        Assert.Contains(commands, c => c.Text.Contains("2. Hauptgang"));

        // Should contain dish names
        Assert.Contains(commands, c => c.Text.Contains("2x Caesar Salad"));
        Assert.Contains(commands, c => c.Text.Contains("1x Wiener Schnitzel"));

        // Should contain modifications
        Assert.Contains(commands, c => c.Text.Contains("- Pommes") && c.IsBold);
        Assert.Contains(commands, c => c.Text.Contains("+ Reis") && c.IsBold);

        // Should contain comment
        Assert.Contains(commands, c => c.Text.Contains("Comment: Well done") && c.IsBold);

        // Should have cut between gangs (not after last)
        var cutCommands = commands.Where(c => c.IsCut).ToList();
        Assert.Single(cutCommands);

        // Gang headers should be red and big
        var gangHeaders = commands.Where(c => c.Text.Contains("Vorspeise") || c.Text.Contains("Hauptgang")).ToList();
        Assert.All(gangHeaders, c =>
        {
            Assert.True(c.IsRed);
            Assert.True(c.IsBig);
            Assert.True(c.IsTall);
        });
    }

    [Fact]
    public void RenderKitchenReceipt_DishesAreTall()
    {
        var template = File.ReadAllText(GetTemplatePath());

        var json = """
            {
              "Title": "Test",
              "TransactionDateTime": "2024-01-01T00:00:00Z",
              "ReceiptNumber": "1",
              "WaiterName": "W",
              "TableNumber": "1",
              "SpecialInstruction": null,
              "HasGangs": true,
              "HasDishes": false,
              "Gangs": [
                {
                  "Id": 1,
                  "Name": "Gang1",
                  "Dishes": [
                    {
                      "Number": 1,
                      "Name": "Item",
                      "GuestPrefix": "",
                      "GuestId": null,
                      "Modifications": { "Removed": [], "Added": [], "HasModifications": false },
                      "Comment": null
                    }
                  ]
                }
              ],
              "Dishes": []
            }
            """;

        var commands = _engine.Render(template, json, LineWidth, BigLineWidth);

        // Dish line should be tall
        var dishCmd = commands.First(c => c.Text.Contains("1x Item"));
        Assert.True(dishCmd.IsTall);
    }

    [Fact]
    public void RenderKitchenReceipt_TableLineCenteredBigBold()
    {
        var template = File.ReadAllText(GetTemplatePath());

        var json = """
            {
              "Title": "Test",
              "TransactionDateTime": "2024-01-01T00:00:00Z",
              "ReceiptNumber": "1",
              "WaiterName": "W",
              "TableNumber": "12",
              "SpecialInstruction": null,
              "HasGangs": false,
              "HasDishes": false,
              "Gangs": [],
              "Dishes": []
            }
            """;

        var commands = _engine.Render(template, json, LineWidth, BigLineWidth);

        var tableCmd = commands.First(c => c.Text.Contains("Tisch: 12"));
        Assert.True(tableCmd.IsBig);
        Assert.True(tableCmd.IsBold);
        // Should be centered in big font width
        Assert.True(tableCmd.Text.StartsWith(" "));
    }

    [Fact]
    public void CompareWithExistingConverter_BasicReceipt()
    {
        // Create a KitchenReceipt via the existing converter
        var receipt = new KitchenReceipt
        {
            Title = "Test Restaurant",
            TransactionDateTime = new DateTime(2024, 3, 15, 14, 30, 0),
            ReceiptNumber = "42",
            WaiterName = "Max Mustermann",
            WaiterId = "W001",
            TableNumber = "5",
            SpecialInstruction = null,
            Gangs = new List<Gang>(),
            Dishes = new List<Dish>()
        };

        var existingConverter = new KitchenReceiptConverter(LineWidth, BigLineWidth);
        var existingCommands = existingConverter.ConvertToPrintCommands(receipt);

        // Render with template engine
        var template = File.ReadAllText(GetTemplatePath());
        var jsonData = JsonSerializer.Serialize(new
        {
            receipt.Title,
            TransactionDateTime = receipt.TransactionDateTime.ToString("o"),
            receipt.ReceiptNumber,
            receipt.WaiterName,
            receipt.TableNumber,
            receipt.SpecialInstruction,
            HasGangs = receipt.Gangs.Count > 0,
            HasDishes = receipt.Dishes != null && receipt.Dishes.Any(),
            receipt.Gangs,
            receipt.Dishes
        });

        var templateCommands = _engine.Render(template, jsonData, LineWidth, BigLineWidth);

        // Compare key structural elements
        // Title should match
        Assert.Equal(existingCommands[0].Text, templateCommands[0].Text);
        Assert.Equal(existingCommands[0].IsRed, templateCommands[0].IsRed);
        Assert.Equal(existingCommands[0].IsBig, templateCommands[0].IsBig);
        Assert.Equal(existingCommands[0].IsTall, templateCommands[0].IsTall);

        // Separator should match
        Assert.Equal(existingCommands[1].Text, templateCommands[1].Text);

        // Empty line
        Assert.Equal(existingCommands[2].Text, templateCommands[2].Text);

        // Date/receipt number line should match formatting
        Assert.Equal(existingCommands[3].Text, templateCommands[3].Text);

        // Waiter name
        Assert.Equal(existingCommands[4].Text, templateCommands[4].Text);

        // Table number
        Assert.Equal(existingCommands[5].Text, templateCommands[5].Text);
        Assert.Equal(existingCommands[5].IsBig, templateCommands[5].IsBig);
        Assert.Equal(existingCommands[5].IsBold, templateCommands[5].IsBold);
    }
}
