Option Strict On
Option Explicit On

Imports System
Imports Nexamas.UI.Layout
Imports Nexamas.UI.Values
Imports SkiaSharp

Namespace Nexamas.UI.Components

    ''' <summary>
    ''' Render-only responsive layout facts for MASKanbanBoard. The board keeps its
    ''' public size contract in MASSizeResolver, while this plan translates the
    ''' current runtime size profile and available bounds into inner chrome/card
    ''' decisions for drawing and hit geometry.
    ''' </summary>
    Friend NotInheritable Class MASKanbanBoardLayoutPlan
        Friend Shared ReadOnly Thresholds As New MASResponsiveLayoutThresholds(
            fullWidthDip:=KanbanBoardTokens.PreferredWidthDip,
            fullHeightDip:=KanbanBoardTokens.PreferredHeightDip,
            denseWidthDip:=680.0F,
            denseHeightDip:=360.0F,
            compactWidthDip:=420.0F,
            compactHeightDip:=260.0F,
            minimalWidthDip:=240.0F,
            minimalHeightDip:=170.0F)

        Friend ReadOnly Property ResponsiveProfile As MASResponsiveLayoutProfile
        Friend ReadOnly Property Mode As MASResponsiveLayoutMode
        Friend ReadOnly Property Dpi As Single
        Friend ReadOnly Property PaddingPx As Single
        Friend ReadOnly Property HeaderHeightPx As Single
        Friend ReadOnly Property HeaderGapPx As Single
        Friend ReadOnly Property FooterHeightPx As Single
        Friend ReadOnly Property FooterGapPx As Single
        Friend ReadOnly Property ColumnGapPx As Single
        Friend ReadOnly Property ColumnPaddingPx As Single
        Friend ReadOnly Property ColumnHeaderHeightPx As Single
        Friend ReadOnly Property ColumnRadiusPx As Single
        Friend ReadOnly Property CardHeightPx As Single
        Friend ReadOnly Property CardGapPx As Single
        Friend ReadOnly Property CardRadiusPx As Single
        Friend ReadOnly Property CardInnerPaddingPx As Single
        Friend ReadOnly Property BadgeWidthPx As Single
        Friend ReadOnly Property BadgeHeightPx As Single
        Friend ReadOnly Property BadgeRadiusPx As Single
        Friend ReadOnly Property BadgeGapPx As Single
        Friend ReadOnly Property MarkerWidthPx As Single
        Friend ReadOnly Property MarkerInsetPx As Single
        Friend ReadOnly Property SummaryWidthPx As Single
        Friend ReadOnly Property MaxVisibleColumns As Integer
        Friend ReadOnly Property MaxVisibleCardsPerColumn As Integer
        Friend ReadOnly Property ShowHeader As Boolean
        Friend ReadOnly Property ShowHeaderSummary As Boolean
        Friend ReadOnly Property ShowFooter As Boolean
        Friend ReadOnly Property ShowCardDetail As Boolean
        Friend ReadOnly Property ShowCardBadge As Boolean
        Friend ReadOnly Property ShowColumnCountPill As Boolean

        Private Sub New(profile As MASResponsiveLayoutProfile,
                        paddingPx As Single,
                        headerHeightPx As Single,
                        headerGapPx As Single,
                        footerHeightPx As Single,
                        footerGapPx As Single,
                        columnGapPx As Single,
                        columnPaddingPx As Single,
                        columnHeaderHeightPx As Single,
                        columnRadiusPx As Single,
                        cardHeightPx As Single,
                        cardGapPx As Single,
                        cardRadiusPx As Single,
                        cardInnerPaddingPx As Single,
                        badgeWidthPx As Single,
                        badgeHeightPx As Single,
                        badgeRadiusPx As Single,
                        badgeGapPx As Single,
                        markerWidthPx As Single,
                        markerInsetPx As Single,
                        summaryWidthPx As Single,
                        maxVisibleColumns As Integer,
                        maxVisibleCardsPerColumn As Integer,
                        showHeader As Boolean,
                        showHeaderSummary As Boolean,
                        showFooter As Boolean,
                        showCardDetail As Boolean,
                        showCardBadge As Boolean,
                        showColumnCountPill As Boolean)
            Dim safeProfile As MASResponsiveLayoutProfile = If(profile, MASResponsiveLayoutResolver.FromLogicalSize(MASSizeLayoutIntegrationContext.Empty, SKSize.Empty, MASSize.Default, Thresholds))
            Me.ResponsiveProfile = safeProfile
            Me.Mode = safeProfile.Mode
            Me.Dpi = safeProfile.DpiScale
            Me.PaddingPx = PositiveOrZero(paddingPx)
            Me.HeaderHeightPx = PositiveOrZero(headerHeightPx)
            Me.HeaderGapPx = PositiveOrZero(headerGapPx)
            Me.FooterHeightPx = PositiveOrZero(footerHeightPx)
            Me.FooterGapPx = PositiveOrZero(footerGapPx)
            Me.ColumnGapPx = PositiveOrZero(columnGapPx)
            Me.ColumnPaddingPx = PositiveOrZero(columnPaddingPx)
            Me.ColumnHeaderHeightPx = PositiveOrZero(columnHeaderHeightPx)
            Me.ColumnRadiusPx = PositiveOrZero(columnRadiusPx)
            Me.CardHeightPx = PositiveOrZero(cardHeightPx)
            Me.CardGapPx = PositiveOrZero(cardGapPx)
            Me.CardRadiusPx = PositiveOrZero(cardRadiusPx)
            Me.CardInnerPaddingPx = PositiveOrZero(cardInnerPaddingPx)
            Me.BadgeWidthPx = PositiveOrZero(badgeWidthPx)
            Me.BadgeHeightPx = PositiveOrZero(badgeHeightPx)
            Me.BadgeRadiusPx = PositiveOrZero(badgeRadiusPx)
            Me.BadgeGapPx = PositiveOrZero(badgeGapPx)
            Me.MarkerWidthPx = PositiveOrZero(markerWidthPx)
            Me.MarkerInsetPx = PositiveOrZero(markerInsetPx)
            Me.SummaryWidthPx = PositiveOrZero(summaryWidthPx)
            Me.MaxVisibleColumns = Math.Max(1, maxVisibleColumns)
            Me.MaxVisibleCardsPerColumn = Math.Max(1, maxVisibleCardsPerColumn)
            Me.ShowHeader = showHeader
            Me.ShowHeaderSummary = showHeaderSummary
            Me.ShowFooter = showFooter
            Me.ShowCardDetail = showCardDetail
            Me.ShowCardBadge = showCardBadge
            Me.ShowColumnCountPill = showColumnCountPill
        End Sub

        Friend Shared Function Create(profile As MASResponsiveLayoutProfile) As MASKanbanBoardLayoutPlan
            Dim safeProfile As MASResponsiveLayoutProfile = If(profile, MASResponsiveLayoutResolver.FromLogicalSize(MASSizeLayoutIntegrationContext.Empty, SKSize.Empty, MASSize.Default, Thresholds))
            Dim chromeScale As Single = safeProfile.ChromeScale
            Dim gapScale As Single = safeProfile.GapScale
            Dim contentScale As Single = safeProfile.ContentScale
            Dim dpi As Single = safeProfile.DpiScale

            Dim showHeader As Boolean = safeProfile.Mode <> MASResponsiveLayoutMode.Collapsed
            Dim showHeaderSummary As Boolean = safeProfile.Mode = MASResponsiveLayoutMode.Full OrElse safeProfile.Mode = MASResponsiveLayoutMode.Dense
            Dim showFooter As Boolean = safeProfile.Mode = MASResponsiveLayoutMode.Full OrElse safeProfile.Mode = MASResponsiveLayoutMode.Dense OrElse safeProfile.Mode = MASResponsiveLayoutMode.Compact
            Dim showCardDetail As Boolean = safeProfile.Mode = MASResponsiveLayoutMode.Full OrElse safeProfile.Mode = MASResponsiveLayoutMode.Dense
            Dim showCardBadge As Boolean = safeProfile.Mode <> MASResponsiveLayoutMode.Minimal AndAlso safeProfile.Mode <> MASResponsiveLayoutMode.Collapsed
            Dim showColumnCountPill As Boolean = safeProfile.Mode <> MASResponsiveLayoutMode.Collapsed

            Dim maxColumns As Integer
            Select Case safeProfile.Mode
                Case MASResponsiveLayoutMode.Full
                    maxColumns = KanbanBoardTokens.MaxVisibleColumns
                Case MASResponsiveLayoutMode.Dense
                    maxColumns = Math.Min(3, KanbanBoardTokens.MaxVisibleColumns)
                Case MASResponsiveLayoutMode.Compact
                    maxColumns = 2
                Case Else
                    maxColumns = 1
            End Select

            Dim maxCards As Integer
            Select Case safeProfile.Mode
                Case MASResponsiveLayoutMode.Full
                    maxCards = KanbanBoardTokens.MaxVisibleCardsPerColumn
                Case MASResponsiveLayoutMode.Dense
                    maxCards = Math.Min(4, KanbanBoardTokens.MaxVisibleCardsPerColumn)
                Case MASResponsiveLayoutMode.Compact
                    maxCards = Math.Min(3, KanbanBoardTokens.MaxVisibleCardsPerColumn)
                Case Else
                    maxCards = Math.Min(2, KanbanBoardTokens.MaxVisibleCardsPerColumn)
            End Select

            Return New MASKanbanBoardLayoutPlan(
                profile:=safeProfile,
                paddingPx:=ScaleDip(KanbanBoardTokens.PaddingDip, dpi, chromeScale),
                headerHeightPx:=If(showHeader, ScaleDip(KanbanBoardTokens.HeaderHeightDip, dpi, chromeScale), 0.0F),
                headerGapPx:=If(showHeader, ScaleDip(10.0F, dpi, gapScale), 0.0F),
                footerHeightPx:=If(showFooter, ScaleDip(KanbanBoardTokens.FooterHeightDip, dpi, chromeScale), 0.0F),
                footerGapPx:=If(showFooter, ScaleDip(8.0F, dpi, gapScale), 0.0F),
                columnGapPx:=ScaleDip(KanbanBoardTokens.ColumnGapDip, dpi, gapScale),
                columnPaddingPx:=ScaleDip(KanbanBoardTokens.ColumnPaddingDip, dpi, chromeScale),
                columnHeaderHeightPx:=ScaleDip(KanbanBoardTokens.ColumnHeaderHeightDip, dpi, chromeScale),
                columnRadiusPx:=ScaleDip(KanbanBoardTokens.ColumnRadiusDip, dpi, chromeScale),
                cardHeightPx:=ScaleDip(If(showCardDetail, KanbanBoardTokens.CardHeightDip, 48.0F), dpi, contentScale),
                cardGapPx:=ScaleDip(KanbanBoardTokens.CardGapDip, dpi, gapScale),
                cardRadiusPx:=ScaleDip(KanbanBoardTokens.CardRadiusDip, dpi, chromeScale),
                cardInnerPaddingPx:=ScaleDip(10.0F, dpi, chromeScale),
                badgeWidthPx:=ScaleDip(KanbanBoardTokens.BadgeWidthDip, dpi, chromeScale),
                badgeHeightPx:=ScaleDip(KanbanBoardTokens.BadgeHeightDip, dpi, chromeScale),
                badgeRadiusPx:=ScaleDip(KanbanBoardTokens.BadgeRadiusDip, dpi, chromeScale),
                badgeGapPx:=ScaleDip(8.0F, dpi, gapScale),
                markerWidthPx:=ScaleDip(2.0F, dpi, chromeScale),
                markerInsetPx:=ScaleDip(10.0F, dpi, gapScale),
                summaryWidthPx:=ScaleDip(220.0F, dpi, chromeScale),
                maxVisibleColumns:=maxColumns,
                maxVisibleCardsPerColumn:=maxCards,
                showHeader:=showHeader,
                showHeaderSummary:=showHeaderSummary,
                showFooter:=showFooter,
                showCardDetail:=showCardDetail,
                showCardBadge:=showCardBadge,
                showColumnCountPill:=showColumnCountPill)
        End Function

        Friend Function EnsureVisibleColumnIndex(selectedIndex As Integer,
                                                 currentLeftIndex As Integer,
                                                 columnCount As Integer) As Integer
            Return EnsureVisibleIndex(selectedIndex, currentLeftIndex, columnCount, MaxVisibleColumns)
        End Function

        Friend Function EnsureVisibleCardIndex(selectedIndex As Integer,
                                               currentTopIndex As Integer,
                                               cardCount As Integer) As Integer
            Return EnsureVisibleIndex(selectedIndex, currentTopIndex, cardCount, MaxVisibleCardsPerColumn)
        End Function

        Private Shared Function EnsureVisibleIndex(selectedIndex As Integer,
                                                   currentStartIndex As Integer,
                                                   itemCount As Integer,
                                                   visibleCapacity As Integer) As Integer
            If itemCount <= 0 Then Return 0
            Dim capacity As Integer = Math.Max(1, visibleCapacity)
            Dim maxStart As Integer = Math.Max(0, itemCount - capacity)
            Dim start As Integer = Math.Max(0, Math.Min(currentStartIndex, maxStart))
            If selectedIndex < 0 Then Return start
            If selectedIndex < start Then Return Math.Max(0, selectedIndex)
            If selectedIndex >= start + capacity Then Return Math.Max(0, Math.Min(maxStart, selectedIndex - capacity + 1))
            Return start
        End Function

        Private Shared Function ScaleDip(valueDip As Single, dpi As Single, scale As Single) As Single
            If Single.IsNaN(valueDip) OrElse Single.IsInfinity(valueDip) OrElse valueDip <= 0.0F Then Return 0.0F
            Dim safeDpi As Single = If(Single.IsNaN(dpi) OrElse Single.IsInfinity(dpi) OrElse dpi <= 0.0F, 1.0F, dpi)
            Dim safeScale As Single = If(Single.IsNaN(scale) OrElse Single.IsInfinity(scale) OrElse scale <= 0.0F, 1.0F, scale)
            Return valueDip * safeDpi * safeScale
        End Function

        Private Shared Function PositiveOrZero(value As Single) As Single
            If Single.IsNaN(value) OrElse Single.IsInfinity(value) OrElse value < 0.0F Then Return 0.0F
            Return value
        End Function
    End Class

End Namespace
