using Microsoft.Playwright;
using Tests.E2e.Infra;
using Tests.E2e.PageObjectModels;
using Xunit.Abstractions;

namespace Tests.E2e;

public class SystemCardTests(
    PlaywrightFixture fixture,
    ITestOutputHelper output) : E2ETestBase(fixture, output) {
    private readonly PlaywrightFixture _fixture = fixture;
    private readonly ITestOutputHelper _output = output;

    // ============================================================
    // Rename / Clone / Delete Flow
    // ============================================================

    [Fact]
    public async Task User_Can_Rename_Clone_And_Delete_System() {
        (IBrowserContext context, IPage page) = await CreatePageAsync();

        var originalName = $"e2e-sys-{Guid.NewGuid():N}"[..16];
        var renamedName = $"e2e-sys-rn-{Guid.NewGuid():N}"[..16];
        var cloneName = $"e2e-sys-cl-{Guid.NewGuid():N}"[..16];

        try {
            await page.GotoAsync($"{_fixture.BaseUrl}/systems/list");

            var list = new SystemsListPom(page);
            await list.AssertLoadedAsync();

            await list.AddSystemAsync(originalName);

            if (!page.Url.Contains($"/resources/systems/{originalName}",
                    StringComparison.OrdinalIgnoreCase))
                await list.OpenSystemAsync(originalName);

            var card = new SystemCardPom(page);
            await card.AssertVisibleAsync(originalName);

            // -------------------------
            // Rename
            // -------------------------
            await card.RenameAsync(originalName, renamedName);
            await card.AssertVisibleAsync(renamedName);

            // -------------------------
            // Clone
            // -------------------------
            await card.CloneAsync(renamedName, cloneName);
            await card.AssertVisibleAsync(cloneName);

            // -------------------------
            // Delete clone
            // -------------------------
            await card.DeleteAsync(cloneName);
            await page.WaitForURLAsync("**/systems/list");

            // Delete renamed original
            await page.GotoAsync($"{_fixture.BaseUrl}/resources/systems/{renamedName}");
            await card.AssertVisibleAsync(renamedName);

            await card.DeleteAsync(renamedName);
            await page.WaitForURLAsync("**/systems/list");
        }
        catch (Exception) {
            _output.WriteLine("TEST FAILED — Capturing diagnostics");
            _output.WriteLine($"Current URL: {page.Url}");

            var html = await page.ContentAsync();
            _output.WriteLine("==== DOM SNAPSHOT START ====");
            _output.WriteLine(html);
            _output.WriteLine("==== DOM SNAPSHOT END ====");

            throw;
        }
        finally {
            await context.CloseAsync();
        }
    }

    // ============================================================
    // Edit Flow
    // ============================================================

    [Fact]
    public async Task User_Can_Edit_And_Save_System() {
        (IBrowserContext context, IPage page) = await CreatePageAsync();
        var name = $"e2e-sys-edit-{Guid.NewGuid():N}"[..16];

        try {
            await page.GotoAsync($"{_fixture.BaseUrl}/systems/list");

            var list = new SystemsListPom(page);
            await list.AddSystemAsync(name);

            if (!page.Url.Contains($"/resources/systems/{name}",
                    StringComparison.OrdinalIgnoreCase))
                await list.OpenSystemAsync(name);

            var card = new SystemCardPom(page);
            await card.AssertVisibleAsync(name);

            await card.BeginEditAsync(name);

            // Edit fields
            await card.TypeSelect(name).SelectOptionAsync(new SelectOptionValue { Index = 0 });
            await card.OsInput(name).FillAsync("Ubuntu 22.04");
            await card.CoresInput(name).FillAsync("8");
            await card.RamInput(name).FillAsync("16");

            await card.SaveAsync(name);

            // Verify read mode restored
            await Assertions.Expect(card.EditButton(name)).ToBeVisibleAsync();
        }
        finally {
            await context.CloseAsync();
        }
    }

    // ============================================================
    // Cancel Edit
    // ============================================================

    [Fact]
    public async Task User_Can_Cancel_System_Edit() {
        (IBrowserContext context, IPage page) = await CreatePageAsync();
        var name = $"e2e-sys-cancel-{Guid.NewGuid():N}"[..16];

        try {
            await page.GotoAsync($"{_fixture.BaseUrl}/systems/list");

            var list = new SystemsListPom(page);
            await list.AddSystemAsync(name);

            if (!page.Url.Contains($"/resources/systems/{name}",
                    StringComparison.OrdinalIgnoreCase))
                await list.OpenSystemAsync(name);

            var card = new SystemCardPom(page);
            await card.AssertVisibleAsync(name);

            await card.BeginEditAsync(name);

            await card.OsInput(name).FillAsync("Should Not Save");

            await card.CancelAsync(name);

            await Assertions.Expect(card.EditButton(name)).ToBeVisibleAsync();
        }
        finally {
            await context.CloseAsync();
        }
    }

    // ============================================================
    // Drive Flow
    // ============================================================

    [Fact]
    public async Task User_Can_Add_And_Edit_System_Drive() {
        (IBrowserContext context, IPage page) = await CreatePageAsync();
        var name = $"e2e-sys-drive-{Guid.NewGuid():N}"[..16];

        try {
            await page.GotoAsync($"{_fixture.BaseUrl}/systems/list");

            var list = new SystemsListPom(page);
            await list.AddSystemAsync(name);

            if (!page.Url.Contains($"/resources/systems/{name}",
                    StringComparison.OrdinalIgnoreCase))
                await list.OpenSystemAsync(name);

            var card = new SystemCardPom(page);
            await card.AssertVisibleAsync(name);

            await card.AddDriveAsync(name, "ssd", 512);
        }
        finally {
            await context.CloseAsync();
        }
    }


    [Fact]
    public async Task User_Can_Add_And_Remove_Tags_From_System_Card() {
        (IBrowserContext context, IPage page) = await CreatePageAsync();
        var name = $"e2e-ap-{Guid.NewGuid():N}"[..16];

        try {
            await page.GotoAsync($"{_fixture.BaseUrl}/systems/list");

            var list = new SystemsListPom(page);
            await list.AssertLoadedAsync();

            await list.AddSystemAsync(name);
            await page.WaitForURLAsync($"**/resources/systems/{name}");

            var card = new SystemCardPom(page);
            await card.AssertVisibleAsync(name);

            TagsPom tags = card.Tags;

            // -------------------------------------------------
            // Add multiple tags in one modal interaction
            // -------------------------------------------------

            await tags.AddTagsAsync("system", "Foo", "Bar", "Baz");

            await tags.AssertTagVisibleAsync("system", "Foo");
            await tags.AssertTagVisibleAsync("system", "Bar");
            await tags.AssertTagVisibleAsync("system", "Baz");

            // -------------------------------------------------
            // Remove a single tag
            // -------------------------------------------------

            await tags.RemoveTagAsync("system", "Bar");

            await tags.AssertTagNotVisibleAsync("system", "Bar");
            await tags.AssertTagVisibleAsync("system", "Foo");
            await tags.AssertTagVisibleAsync("system", "Baz");

            // -------------------------------------------------
            // Reload to verify persistence
            // -------------------------------------------------

            await page.ReloadAsync();

            await tags.AssertTagVisibleAsync("system", "Foo");
            await tags.AssertTagVisibleAsync("system", "Baz");
            await tags.AssertTagNotVisibleAsync("system", "Bar");

            await context.CloseAsync();
        }
        finally {
            await context.CloseAsync();
        }
    }
}
