using Inspectron.Epson.Templates.Configuration;
using Inspectron.Epson.Templates.Interpreter;
using Inspectron.Epson.Templates.Language;
using Inspectron.Epson.Templates.Language.Nodes;

namespace Inspectron.Epson.Templates.Tests.Interpreter;

public class InterpreterBindingTests
{
    private readonly PrinterProfile _profile = new("test", "Test Printer", 48, 24, false);

    private TemplateNode Parse(string source)
    {
        var lexer = new Lexer(source);
        var parser = new Parser(lexer.Tokenize().Tokens);
        return parser.Parse().Template;
    }

    [Fact]
    public void Interpret_SimpleBinding_ResolvesValue()
    {
        var template = Parse("{Name}");
        var interpreter = new TemplateInterpreter(_profile);
        var commands = interpreter.Interpret(template, """{"Name": "John"}""");

        Assert.Contains(commands, c => c.Text == "John");
    }

    [Fact]
    public void Interpret_NestedBinding_ResolvesNestedValue()
    {
        var template = Parse("{Person.Name}");
        var interpreter = new TemplateInterpreter(_profile);
        var commands = interpreter.Interpret(template, """{"Person": {"Name": "Jane"}}""");

        Assert.Contains(commands, c => c.Text == "Jane");
    }

    [Fact]
    public void Interpret_NumericBinding_OutputsNumber()
    {
        var template = Parse("{Amount}");
        var interpreter = new TemplateInterpreter(_profile);
        var commands = interpreter.Interpret(template, """{"Amount": 42}""");

        Assert.Contains(commands, c => c.Text == "42");
    }

    [Fact]
    public void Interpret_NumericBinding_WithFormat_FormatsNumber()
    {
        var template = Parse("{Price:F2}");
        var interpreter = new TemplateInterpreter(_profile);
        var commands = interpreter.Interpret(template, """{"Price": 19.5}""");

        Assert.Contains(commands, c => c.Text == "19.50");
    }

    [Fact]
    public void Interpret_DateBinding_WithFormat_FormatsDate()
    {
        var template = Parse("{Date:dd-MMM-yy}");
        var interpreter = new TemplateInterpreter(_profile);
        var commands = interpreter.Interpret(template, """{"Date": "2024-03-15T14:30:00"}""");

        var cmd = commands.FirstOrDefault(c => c.Text.Contains("Mar"));
        Assert.NotNull(cmd);
        Assert.Contains("15", cmd.Text);
    }

    [Fact]
    public void Interpret_MissingBinding_OutputsEmptyString()
    {
        var template = Parse("{Missing}");
        var interpreter = new TemplateInterpreter(_profile);
        var commands = interpreter.Interpret(template, """{"Other": "value"}""");

        Assert.Contains(commands, c => c.Text == "");
    }

    [Fact]
    public void Interpret_NullBinding_OutputsEmptyString()
    {
        var template = Parse("{Value}");
        var interpreter = new TemplateInterpreter(_profile);
        var commands = interpreter.Interpret(template, """{"Value": null}""");

        Assert.Contains(commands, c => c.Text == "");
    }

    [Fact]
    public void Interpret_ArrayCountBinding_OutputsCount()
    {
        var template = Parse("{Items.count}");
        var interpreter = new TemplateInterpreter(_profile);
        var commands = interpreter.Interpret(template, """{"Items": [1, 2, 3, 4, 5]}""");

        Assert.Contains(commands, c => c.Text == "5");
    }

    [Fact]
    public void Interpret_BoolBinding_OutputsTrue()
    {
        var template = Parse("{Flag}");
        var interpreter = new TemplateInterpreter(_profile);
        var commands = interpreter.Interpret(template, """{"Flag": true}""");

        Assert.Contains(commands, c => c.Text == "true");
    }

    [Fact]
    public void Interpret_BoolBinding_OutputsFalse()
    {
        var template = Parse("{Flag}");
        var interpreter = new TemplateInterpreter(_profile);
        var commands = interpreter.Interpret(template, """{"Flag": false}""");

        Assert.Contains(commands, c => c.Text == "false");
    }

    [Fact]
    public void Interpret_BindingInStyledText_AppliesStyleToResolvedValue()
    {
        var template = Parse("#bold# {Name} #");
        var interpreter = new TemplateInterpreter(_profile);
        var commands = interpreter.Interpret(template, """{"Name": "Test"}""");

        var cmd = commands.FirstOrDefault(c => c.Text.Contains("Test"));
        Assert.NotNull(cmd);
        Assert.True(cmd.IsBold);
    }
}
