using Motus.Recorder.PageAnalysis;
using Motus.Recorder.PomEmit;

namespace Motus.Recorder.Tests.PomEmit;

[TestClass]
public class PomEmitterTests
{
    private readonly PomEmitter _emitter = new();

    private static DiscoveredElement Element(
        string memberName,
        string? selector,
        string tag = "input",
        string? type = "text",
        string? id = null,
        int? formIndex = null,
        int elementIndex = 0)
        => new(
            new PageElementInfo(tag, type, id, null, null, null, null, null, null, null, formIndex, elementIndex),
            selector,
            memberName);

    [TestMethod]
    public void Emit_EmptyElements_ProducesValidClass()
    {
        var code = _emitter.Emit([]);

        Assert.IsTrue(code.Contains("// <auto-generated/>"));
        Assert.IsTrue(code.Contains("using Motus.Abstractions;"));
        Assert.IsTrue(code.Contains("namespace Motus.Generated;"));
        Assert.IsTrue(code.Contains("public partial class GeneratedPage"));
        Assert.IsTrue(code.Contains("private readonly IPage _page;"));
        Assert.IsTrue(code.Contains("public Task NavigateAsync()"));
    }

    [TestMethod]
    public void Emit_CustomOptions_UsesOptions()
    {
        var options = new PomEmitOptions
        {
            Namespace = "MyApp.Pages",
            ClassName = "LoginPage",
            PageUrl = "https://example.com/login"
        };

        var code = _emitter.Emit([], options);

        Assert.IsTrue(code.Contains("namespace MyApp.Pages;"));
        Assert.IsTrue(code.Contains("public partial class LoginPage"));
        Assert.IsTrue(code.Contains("LoginPage(IPage page)"));
        Assert.IsTrue(code.Contains("https://example.com/login"));
    }

    [TestMethod]
    public void Emit_WithSelector_EmitsLocatorProperty()
    {
        var elements = new[]
        {
            Element("EmailInput", "#email")
        };

        var code = _emitter.Emit(elements);

        Assert.IsTrue(code.Contains("""public ILocator EmailInput => _page.Locator("#email");"""));
    }

    [TestMethod]
    public void Emit_WithoutSelector_EmitsTodoComment()
    {
        var elements = new[]
        {
            Element("UnknownElement", null, tag: "input", elementIndex: 3)
        };

        var code = _emitter.Emit(elements);

        Assert.IsTrue(code.Contains("// TODO:"));
        Assert.IsTrue(code.Contains("UnknownElement"));
    }

    [TestMethod]
    public void Emit_MultipleElements_EmitsAll()
    {
        var elements = new[]
        {
            Element("EmailInput", "#email"),
            Element("PasswordInput", "#password"),
            Element("SignInButton", "#submit", tag: "button", type: null),
        };

        var code = _emitter.Emit(elements);

        Assert.IsTrue(code.Contains("EmailInput"));
        Assert.IsTrue(code.Contains("PasswordInput"));
        Assert.IsTrue(code.Contains("SignInButton"));
    }

    [TestMethod]
    public void Emit_FormGroup_GeneratesActionMethod()
    {
        var elements = new[]
        {
            Element("EmailInput", "#email", formIndex: 0, elementIndex: 0),
            Element("PasswordInput", "#password", formIndex: 0, elementIndex: 1),
            Element("SignInButton", "#submit", tag: "button", type: null, formIndex: 0, elementIndex: 2),
        };

        var code = _emitter.Emit(elements);

        Assert.IsTrue(code.Contains("// Form actions"));
        Assert.IsTrue(code.Contains("public async Task"));
        Assert.IsTrue(code.Contains("await EmailInput.FillAsync("));
        Assert.IsTrue(code.Contains("await PasswordInput.FillAsync("));
        Assert.IsTrue(code.Contains("await SignInButton.ClickAsync();"));
    }

    [TestMethod]
    public void Emit_NoFormWithSubmit_NoActionMethod()
    {
        var elements = new[]
        {
            Element("EmailInput", "#email", formIndex: null),
            Element("SearchButton", "#search", tag: "button", type: null, formIndex: null),
        };

        var code = _emitter.Emit(elements);

        Assert.IsFalse(code.Contains("// Form actions"));
    }

    [TestMethod]
    public void Emit_SelectorWithSpecialChars_IsEscaped()
    {
        var elements = new[]
        {
            Element("NameInput", "[data-testid=\"name\"]")
        };

        var code = _emitter.Emit(elements);

        Assert.IsTrue(code.Contains("[data-testid=\\\"name\\\"]"));
    }

    [TestMethod]
    public void Emit_UrlWithSpecialChars_IsEscaped()
    {
        var options = new PomEmitOptions
        {
            PageUrl = "https://example.com/path?q=a&b=c"
        };

        var code = _emitter.Emit([], options);

        Assert.IsTrue(code.Contains("https://example.com/path?q=a&b=c"));
    }

    [TestMethod]
    public void Emit_ClassIsPartial()
    {
        var code = _emitter.Emit([]);
        Assert.IsTrue(code.Contains("public partial class"));
    }
}
