namespace Spectre.Console.Tests.Unit;

[ExpectationPath("Widgets/Grid")]
public sealed class GridTests
{
    public sealed class TheAddColumnMethod
    {
        [Fact]
        public void Should_Throw_If_Rows_Are_Not_Empty()
        {
            // Given
            var grid = new Grid();
            grid.AddColumn();
            grid.AddRow("Hello World!");

            // When
            var result = Record.Exception(() => grid.AddColumn());

            // Then
            result.ShouldBeOfType<InvalidOperationException>()
                .Message.ShouldBe("Cannot add new columns to grid with existing rows.");
        }
    }

    public sealed class TheAddRowMethod
    {
        [Fact]
        public void Should_Throw_If_Rows_Are_Null()
        {
            // Given
            var grid = new Grid();

            // When
            var result = Record.Exception(() => grid.AddRow(null!));

            // Then
            result.ShouldBeOfType<ArgumentNullException>()
                .ParamName.ShouldBe("columns");
        }

        [Fact]
        public void Should_Add_Empty_Items_If_User_Provides_Less_Row_Items_Than_Columns()
        {
            // Given
            var grid = new Grid();
            grid.AddColumn();
            grid.AddColumn();

            // When
            grid.AddRow("Foo");

            // Then
            grid.Rows.Count.ShouldBe(1);
        }

        [Fact]
        public void Should_Throw_If_Row_Columns_Are_Greater_Than_Number_Of_Columns()
        {
            // Given
            var grid = new Grid();
            grid.AddColumn();

            // When
            var result = Record.Exception(() => grid.AddRow("Foo", "Bar"));

            // Then
            result.ShouldBeOfType<InvalidOperationException>();
            result.Message.ShouldBe("The number of row columns are greater than the number of grid columns.");
        }
    }

    [ExpectationPath("AddEmptyRow")]
    public sealed class TheAddEmptyRowMethod
    {
        [Fact]
        [Expectation("Render")]
        public Task Should_Add_Empty_Row()
        {
            // Given
            var console = new TestConsole();
            var grid = new Grid();
            grid.AddColumns(2);
            grid.AddRow("Foo", "Bar");
            grid.AddEmptyRow();
            grid.AddRow("Qux", "Corgi");
            grid.AddEmptyRow();

            // When
            console.Write(grid);

            // Then
            return Verifier.Verify(console.Output);
        }
    }

    [Fact]
    [Expectation("Render")]
    public Task Should_Render_Grid_Correctly()
    {
        // Given
        var console = new TestConsole();
        var grid = new Grid();
        grid.AddColumn();
        grid.AddColumn();
        grid.AddColumn();
        grid.AddRow("Qux", "Corgi", "Waldo");
        grid.AddRow("Grault", "Garply", "Fred");

        // When
        console.Write(grid);

        // Then
        return Verifier.Verify(console.Output);
    }

    [Fact]
    [Expectation("Render_2")]
    public Task Should_Render_Grid_Correctly_2()
    {
        var console = new TestConsole();
        var grid = new Grid();
        grid.AddColumn(new GridColumn { NoWrap = true });
        grid.AddColumn(new GridColumn { Padding = new Padding(2, 0, 0, 0) });
        grid.AddRow("[bold]Options[/]", string.Empty);
        grid.AddRow("  [blue]-h[/], [blue]--help[/]", "Show command line help.");
        grid.AddRow("  [blue]-c[/], [blue]--configuration[/]", "The configuration to run for.\nThe default for most projects is [green]Debug[/].");

        // When
        console.Write(grid);

        // Then
        return Verifier.Verify(console.Output);
    }

    [Fact]
    [Expectation("Render_Alignment")]
    public Task Should_Render_Grid_Column_Alignment_Correctly()
    {
        // Given
        var console = new TestConsole();
        var grid = new Grid();
        grid.AddColumn(new GridColumn { Alignment = Justify.Right });
        grid.AddColumn(new GridColumn { Alignment = Justify.Center });
        grid.AddColumn(new GridColumn { Alignment = Justify.Left });
        grid.AddRow("Foo", "Bar", "Baz");
        grid.AddRow("Qux", "Corgi", "Waldo");
        grid.AddRow("Grault", "Garply", "Fred");

        // When
        console.Write(grid);

        // Then
        return Verifier.Verify(console.Output);
    }

    [Fact]
    [Expectation("Render_Padding")]
    public Task Should_Use_Default_Padding()
    {
        // Given
        var console = new TestConsole();
        var grid = new Grid();
        grid.AddColumns(3);
        grid.AddRow("Foo", "Bar", "Baz");
        grid.AddRow("Qux", "Corgi", "Waldo");
        grid.AddRow("Grault", "Garply", "Fred");

        // When
        console.Write(grid);

        // Then
        return Verifier.Verify(console.Output);
    }

    [Fact]
    [Expectation("Render_ExplicitPadding")]
    public Task Should_Render_Explicit_Grid_Column_Padding_Correctly()
    {
        // Given
        var console = new TestConsole();
        var grid = new Grid();
        grid.AddColumn(new GridColumn { Padding = new Padding(3, 0, 0, 0) });
        grid.AddColumn(new GridColumn { Padding = new Padding(0, 0, 0, 0) });
        grid.AddColumn(new GridColumn { Padding = new Padding(0, 0, 3, 0) });
        grid.AddRow("Foo", "Bar", "Baz");
        grid.AddRow("Qux", "Corgi", "Waldo");
        grid.AddRow("Grault", "Garply", "Fred");

        // When
        console.Write(grid);

        // Then
        return Verifier.Verify(console.Output);
    }

    [Fact]
    [Expectation("Render_Cell_Overflow_Crop")]
    public Task Should_Respect_Cell_Content_Overflow_Crop()
    {
        // Given
        var console = new TestConsole().Width(40);
        var grid = new Grid();
        grid.AddColumn(new GridColumn { Width = 15 });
        grid.AddColumn(new GridColumn { Width = 15 });
        grid.AddRow(
            new Text("foo pneumonoultramicroscopicsilicovolcanoconiosis bar").Overflow(Overflow.Crop),
            new Text("Short text"));

        // When
        console.Write(grid);

        // Then
        return Verifier.Verify(console.Output);
    }

    [Fact]
    [Expectation("Render_Cell_Overflow_Ellipsis")]
    public Task Should_Respect_Cell_Content_Overflow_Ellipsis()
    {
        // Given
        var console = new TestConsole().Width(40);
        var grid = new Grid();
        grid.AddColumn(new GridColumn { Width = 15 });
        grid.AddColumn(new GridColumn { Width = 15 });
        grid.AddRow(
            new Text("foo pneumonoultramicroscopicsilicovolcanoconiosis bar").Overflow(Overflow.Ellipsis),
            new Text("Short text"));

        // When
        console.Write(grid);

        // Then
        return Verifier.Verify(console.Output);
    }

    [Fact]
    [Expectation("Render_Cell_Overflow_Fold")]
    public Task Should_Respect_Cell_Content_Overflow_Fold()
    {
        // Given
        var console = new TestConsole().Width(40);
        var grid = new Grid();
        grid.AddColumn(new GridColumn { Width = 15 });
        grid.AddColumn(new GridColumn { Width = 15 });
        grid.AddRow(
            new Text("foo pneumonoultramicroscopicsilicovolcanoconiosis bar").Overflow(Overflow.Fold),
            new Text("Short text"));

        // When
        console.Write(grid);

        // Then
        return Verifier.Verify(console.Output);
    }

    [Fact]
    [Expectation("Render_Cell_Markup_Overflow")]
    public Task Should_Respect_Markup_Content_Overflow_In_Cell()
    {
        // Given
        var console = new TestConsole().Width(40);
        var grid = new Grid();
        grid.AddColumn(new GridColumn { Width = 18 });
        grid.AddColumn(new GridColumn { Width = 15 });
        grid.AddRow(
            new Markup("[yellow]foo[/] [red]pneumonoultramicroscopicsilicovolcanoconiosis[/] [blue]bar[/]").Overflow(Overflow.Ellipsis),
            new Markup("[green]Short text[/]"));

        // When
        console.Write(grid);

        // Then
        return Verifier.Verify(console.Output);
    }

    [Fact]
    [Expectation("Render_Cell_Overflow_With_NoWrap")]
    public Task Should_Respect_Cell_Content_Overflow_With_NoWrap_Column()
    {
        // Given
        var console = new TestConsole().Width(40);
        var grid = new Grid();
        grid.AddColumn(new GridColumn { Width = 15, NoWrap = true });
        grid.AddColumn(new GridColumn { Width = 15 });
        grid.AddRow(
            new Text("foo pneumonoultramicroscopicsilicovolcanoconiosis bar").Overflow(Overflow.Ellipsis),
            new Text("Short text"));

        // When
        console.Write(grid);

        // Then
        return Verifier.Verify(console.Output);
    }
}