Option Strict On
Option Explicit On

Imports System
Imports System.Collections.Generic
Imports Nexamas.UI.DataBinding
Imports Nexamas.UI.Values

Namespace Nexamas.UI.Components

    ''' <summary>
    ''' Friend-only proof that KanbanBoard's source projection can hold a large board
    ''' while the realized drawing/input diagnostics remain bounded to a small board
    ''' window. The gate intentionally avoids timing assertions because execution hosts
    ''' vary; it verifies capacity, stable-key access, scrolling, and selection retention.
    ''' </summary>
    Friend NotInheritable Class MASKanbanBoardLargeBoardWindowingGate

        Private Sub New()
        End Sub

        Friend Shared Function Passes() As Boolean
            Dim failures As IReadOnlyList(Of String) = Evaluate()
            Return failures.Count = 0
        End Function

        Friend Shared Function Evaluate() As IReadOnlyList(Of String)
            Dim failures As New List(Of String)()

            If Not MASKanbanBoardPolicy.HasLargeBoardWindowingProofPath() Then failures.Add("Kanban large-board windowing proof path is missing.")

            Dim columnCount As Integer = KanbanBoardTokens.LargeBoardProofColumns
            Dim cardsPerColumn As Integer = KanbanBoardTokens.LargeBoardProofCardsPerColumn
            Dim totalCards As Integer = KanbanBoardTokens.LargeBoardProofCards
            Dim records As New List(Of Object)(totalCards)

            For columnIndex As Integer = 0 To columnCount - 1
                For cardIndex As Integer = 0 To cardsPerColumn - 1
                    Dim columnKey As String = BuildColumnKey(columnIndex)
                    Dim cardKey As String = BuildCardKey(columnIndex, cardIndex)
                    records.Add(MASKanbanSourceRecord.Create(columnKey,
                                                             "Card " & columnIndex.ToString(System.Globalization.CultureInfo.InvariantCulture) & ":" & cardIndex.ToString(System.Globalization.CultureInfo.InvariantCulture),
                                                             "Column " & columnIndex.ToString(System.Globalization.CultureInfo.InvariantCulture),
                                                             cardKey,
                                                             "Large board proof",
                                                             If(cardIndex Mod 2 = 0, "A", "B")))
                Next
            Next

            Dim source As MASListItemsSource = MASListItemsSource.FromEnumerable(records, AddressOf ResolveProbeKey)
            Dim definition As MASKanbanSourceDefinition = MASKanbanSourceDefinition.Create(
                columnKeyField:="column",
                cardTitleField:="title",
                columnTitleField:="columnTitle",
                cardKeyField:="key",
                cardDetailField:="detail",
                badgeTextField:="badge")

            Dim board As MASKanbanBoard = MASKanbanBoard.Create("Large Kanban")
            board.SetDiagnosticColumnViewportCapacity(KanbanBoardTokens.MaxVisibleColumns)
            board.SetDiagnosticCardViewportCapacity(KanbanBoardTokens.MaxVisibleCardsPerColumn)
            board.SetKanbanSource(source, definition, "MASKanbanBoardLargeBoardWindowingGate")

            If Not board.HasKanbanSource Then failures.Add("Kanban did not retain the large source link.")
            If board.KanbanSourceRevision < 0 Then failures.Add("Kanban source revision was not captured.")
            If board.ColumnCount <> columnCount Then failures.Add("Kanban did not retain the full large-board column count.")
            If board.CardCount <> totalCards Then failures.Add("Kanban did not retain the full large-board card count.")
            If board.GetProjectedCardKeys().Count <> totalCards Then failures.Add("Kanban projected-card key count does not match the large board.")

            Dim firstKey As String = BuildCardKey(0, 0)
            Dim firstWindow As MASKanbanBoardWindowSnapshot = board.CreateBoardWindowSnapshot()
            If firstWindow.TotalColumns <> columnCount Then failures.Add("Initial board-window column total does not match the large board.")
            If firstWindow.TotalCards <> totalCards Then failures.Add("Initial board-window card total does not match the large board.")
            If Not firstWindow.IsBounded Then failures.Add("Initial board-window realizes more cards than requested capacity.")
            If firstWindow.RealizedColumnCount > KanbanBoardTokens.MaxVisibleColumns Then failures.Add("Initial board-window exceeds MaxVisibleColumns.")
            If firstWindow.RealizedCardCount > KanbanBoardTokens.MaxVisibleColumns * KanbanBoardTokens.MaxVisibleCardsPerColumn Then failures.Add("Initial board-window exceeds the bounded card capacity.")
            If Not firstWindow.CoversPartialBoard Then failures.Add("Initial board-window should cover only a partial board for large sources.")
            If Not firstWindow.ContainsCardKey(firstKey) Then failures.Add("Initial board-window does not contain the first stable card key.")

            Dim middleColumn As Integer = columnCount \ 2
            Dim middleCard As Integer = cardsPerColumn \ 2
            Dim middleKey As String = BuildCardKey(middleColumn, middleCard)
            If Not board.EnsureCardVisible(middleKey) Then failures.Add("Kanban could not ensure a middle large-board card visible.")
            Dim middleWindow As MASKanbanBoardWindowSnapshot = board.CreateBoardWindowSnapshot()
            If Not middleWindow.ContainsCardKey(middleKey) Then failures.Add("Middle card was not realized after EnsureCardVisible.")
            If Not middleWindow.IsBounded Then failures.Add("Middle board-window realizes more cards than requested capacity.")
            If board.SelectedCardKey <> middleKey Then failures.Add("Middle-card selection was not retained.")

            Dim lastKey As String = BuildCardKey(columnCount - 1, cardsPerColumn - 1)
            If Not board.EnsureCardVisible(lastKey) Then failures.Add("Kanban could not ensure the final large-board card visible.")
            Dim lastWindow As MASKanbanBoardWindowSnapshot = board.CreateBoardWindowSnapshot()
            If Not lastWindow.ContainsCardKey(lastKey) Then failures.Add("Final card was not realized in the bounded window.")
            If lastWindow.RealizedColumnCount > KanbanBoardTokens.MaxVisibleColumns Then failures.Add("Final board-window exceeds MaxVisibleColumns.")
            If lastWindow.RealizedCardCount > KanbanBoardTokens.MaxVisibleColumns * KanbanBoardTokens.MaxVisibleCardsPerColumn Then failures.Add("Final board-window exceeds the bounded card capacity.")
            If lastWindow.FirstColumnIndex <= 0 Then failures.Add("Final board-window did not scroll away from the first column.")
            If board.SelectedCardKey <> lastKey Then failures.Add("Final-card selection was not retained.")
            If board.KanbanSourceRevision <> lastWindow.ProjectionRevision Then failures.Add("Window snapshot projection revision does not match the board source revision.")

            If Not board.HasBoundedBoardWindow(totalCards, KanbanBoardTokens.MaxVisibleColumns, KanbanBoardTokens.MaxVisibleCardsPerColumn) Then failures.Add("Bounded board-window helper did not recognize the large-board proof.")

            Return failures
        End Function

        Private Shared Function BuildColumnKey(columnIndex As Integer) As String
            Return "column-" & columnIndex.ToString(System.Globalization.CultureInfo.InvariantCulture)
        End Function

        Private Shared Function BuildCardKey(columnIndex As Integer,
                                             cardIndex As Integer) As String
            Return "card-" & columnIndex.ToString(System.Globalization.CultureInfo.InvariantCulture) & "-" & cardIndex.ToString(System.Globalization.CultureInfo.InvariantCulture)
        End Function

        Private Shared Function ResolveProbeKey(item As Object) As String
            Dim record As MASKanbanSourceRecord = TryCast(item, MASKanbanSourceRecord)
            If record Is Nothing Then Return String.Empty
            Dim value As Object = Nothing
            If record.TryGetField("key", value) Then Return Convert.ToString(value, System.Globalization.CultureInfo.InvariantCulture)
            Return String.Empty
        End Function

    End Class

End Namespace
