Option Strict On
Option Explicit On

Imports System
Imports Nexamas.UI.Architecture
Imports Nexamas.UI.Theming
Imports Nexamas.UI.Values
Imports SkiaSharp

Namespace Nexamas.UI.General

    ''' <summary>
    ''' Builds semantic interaction overlay specifications.
    '''
    ''' Architectural Law:
    ''' - Contract-based Build is the preferred path for registered components.
    ''' - Kind/family helpers are only for virtual parts, legacy adapters, or internal
    '''   sub-surfaces that do not have their own registered component identity.
    ''' - This class defines interaction language only; it must not become a universal
    '''   visual template or override component-specific material DNA.
    ''' </summary>
    Friend NotInheritable Class MASVisualInteractionScenarios

        Private Sub New()
        End Sub

#Region "Public Build API"

        Friend Shared Function Build(contract As MASResolvedComponentContract,
                                     state As MASInteractionState,
                                     theme As IMASAppTheme,
                                     Optional intent As MASVisualInteractionIntent = MASVisualInteractionIntent.Normal) As MASVisualInteractionOverlaySpec

            If contract Is Nothing Then Throw New ArgumentNullException(NameOf(contract))
            contract.AssertConsumable()

            If theme Is Nothing Then Throw New ArgumentNullException(NameOf(theme))

            If MASAppThemeContracts.Foundation(theme).Interaction Is Nothing Then
                Throw New InvalidOperationException($"Theme '{theme.Id}' does not provide interaction colors.")
            End If

            Dim interactionProfile As InteractionPersonalityProfiles.InteractionProfile =
                MASInteractionResolver.ResolveProfile(contract)

            Dim personality As InteractionPersonalityProfiles.InteractionPersonalityProfile =
                MASInteractionResolver.ResolvePersonality(contract)

            Dim geometry As MASVisualInteractionGeometryProfiles.InteractionGeometryProfile =
                MASInteractionResolver.ResolveGeometry(contract)

            Return BuildFromProfile(
                state:=MASInteractionResolver.NormalizeState(state),
                interactionProfile:=interactionProfile,
                themeInteraction:=MASAppThemeContracts.Foundation(theme).Interaction,
                personality:=personality,
                geometry:=geometry,
                intent:=intent)

        End Function

        ''' <summary>
        ''' Builds a MAS interaction overlay from official interaction profiles while using
        ''' a component-scoped interaction color source instead of Foundation.Interaction.
        ''' </summary>
        Friend Shared Function Build(contract As MASResolvedComponentContract,
                                     state As MASInteractionState,
                                     interactionTheme As IMASInteractionTheme,
                                     Optional intent As MASVisualInteractionIntent = MASVisualInteractionIntent.Normal) As MASVisualInteractionOverlaySpec

            If contract Is Nothing Then Throw New ArgumentNullException(NameOf(contract))
            contract.AssertConsumable()

            If interactionTheme Is Nothing Then Throw New ArgumentNullException(NameOf(interactionTheme))

            Dim interactionProfile As InteractionPersonalityProfiles.InteractionProfile =
                MASInteractionResolver.ResolveProfile(contract)

            Dim personality As InteractionPersonalityProfiles.InteractionPersonalityProfile =
                MASInteractionResolver.ResolvePersonality(contract)

            Dim geometry As MASVisualInteractionGeometryProfiles.InteractionGeometryProfile =
                MASInteractionResolver.ResolveGeometry(contract)

            Return BuildFromProfile(
                state:=MASInteractionResolver.NormalizeState(state),
                interactionProfile:=interactionProfile,
                themeInteraction:=interactionTheme,
                personality:=personality,
                geometry:=geometry,
                intent:=intent)

        End Function

        ''' <summary>
        ''' Legacy/virtual helper. Use only for internal sub-parts that have no registered
        ''' component identity. Registered components must use contract-based Build.
        ''' </summary>
        Friend Shared Function BuildByKind(state As MASInteractionState,
                                           kind As CommonEnums.ControlKind,
                                           theme As IMASAppTheme,
                                           Optional intent As MASVisualInteractionIntent = MASVisualInteractionIntent.Normal) As MASVisualInteractionOverlaySpec

            If theme Is Nothing Then Throw New ArgumentNullException(NameOf(theme))

            If MASAppThemeContracts.Foundation(theme).Interaction Is Nothing Then
                Throw New InvalidOperationException($"Theme '{theme.Id}' does not provide interaction colors.")
            End If

            Dim family As CommonEnums.SurfaceFamily =
                CommonEnums.MapKindToFamily(kind)

            Return BuildByFamily(
                state:=state,
                family:=family,
                theme:=theme,
                intent:=intent)

        End Function

        ''' <summary>
        ''' Legacy/virtual helper. Use only when a real MASResolvedComponentContract is not available.
        ''' Registered components must prefer contract-based Build.
        ''' </summary>
        Friend Shared Function BuildByFamily(state As MASInteractionState,
                                             family As CommonEnums.SurfaceFamily,
                                             theme As IMASAppTheme,
                                             Optional intent As MASVisualInteractionIntent = MASVisualInteractionIntent.Normal) As MASVisualInteractionOverlaySpec

            If theme Is Nothing Then Throw New ArgumentNullException(NameOf(theme))

            If MASAppThemeContracts.Foundation(theme).Interaction Is Nothing Then
                Throw New InvalidOperationException($"Theme '{theme.Id}' does not provide interaction colors.")
            End If

            Dim interactionProfile As InteractionPersonalityProfiles.InteractionProfile =
                InteractionPersonalityProfiles.ResolveProfile(family)

            Dim personality As InteractionPersonalityProfiles.InteractionPersonalityProfile =
                InteractionPersonalityProfiles.Resolve(family)

            Dim geometry As MASVisualInteractionGeometryProfiles.InteractionGeometryProfile =
                MASVisualInteractionGeometryProfiles.Resolve(family)

            Return BuildFromProfile(
                state:=MASInteractionResolver.NormalizeState(state),
                interactionProfile:=interactionProfile,
                themeInteraction:=MASAppThemeContracts.Foundation(theme).Interaction,
                personality:=personality,
                geometry:=geometry,
                intent:=intent)

        End Function

#End Region

#Region "Geometry API"

        Friend Shared Function ResolveGeometryStateByKind(kind As CommonEnums.ControlKind,
                                                          state As MASInteractionState) As MASVisualInteractionGeometryProfiles.InteractionGeometryStateProfile

            Return MASVisualInteractionGeometryProfiles.ResolveState(kind, state)

        End Function

        Friend Shared Function ResolveGeometryStateByFamily(family As CommonEnums.SurfaceFamily,
                                                            state As MASInteractionState) As MASVisualInteractionGeometryProfiles.InteractionGeometryStateProfile

            Return MASVisualInteractionGeometryProfiles.ResolveState(family, state)

        End Function

#End Region

#Region "Assembler"

        Private Shared Function BuildFromProfile(state As MASInteractionState,
                                                 interactionProfile As InteractionPersonalityProfiles.InteractionProfile,
                                                 themeInteraction As IMASInteractionTheme,
                                                 personality As InteractionPersonalityProfiles.InteractionPersonalityProfile,
                                                 geometry As MASVisualInteractionGeometryProfiles.InteractionGeometryProfile,
                                                 intent As MASVisualInteractionIntent) As MASVisualInteractionOverlaySpec

            Dim normalized As MASInteractionState = MASInteractionResolver.NormalizeState(state)

            Dim spec As New MASVisualInteractionOverlaySpec With {
                .FillEnabled = False,
                .RingEnabled = False,
                .Fill = SKColors.Transparent,
                .Ring = SKColors.Transparent,
                .FillBlendMode = SKBlendMode.SrcOver,
                .ExtraFillInsetPx = 0.0F,
                .ExtraRingInsetPx = 0.0F,
                .Shape = MASVisualInteractionOverlayShape.Closed,
                .State = normalized
            }

            Select Case normalized

                Case MASInteractionState.None
                    Return spec

                Case MASInteractionState.Hovered
                    ApplyState(spec, interactionProfile.Hover, ResolveThemeState(themeInteraction, normalized, intent))
                    ApplyHoverBehavior(spec, personality)
                    ApplyGeometryState(spec, MASVisualInteractionGeometryProfiles.ResolveState(geometry, normalized))

                Case MASInteractionState.Pressed
                    ApplyState(spec, interactionProfile.Pressed, ResolveThemeState(themeInteraction, normalized, intent))
                    ApplyPressedBehavior(spec, personality)
                    ApplyGeometryState(spec, MASVisualInteractionGeometryProfiles.ResolveState(geometry, normalized))

                Case MASInteractionState.Selected
                    ApplyState(spec, interactionProfile.Selected, ResolveThemeState(themeInteraction, normalized, intent))
                    ApplySelectedBehavior(spec, personality)
                    ApplyGeometryState(spec, MASVisualInteractionGeometryProfiles.ResolveState(geometry, normalized))

                Case MASInteractionState.Focused
                    ApplyState(spec, interactionProfile.Focused, ResolveThemeState(themeInteraction, normalized, intent))
                    ApplyFocusedBehavior(spec, personality)
                    ApplyGeometryState(spec, MASVisualInteractionGeometryProfiles.ResolveState(geometry, normalized))

                Case MASInteractionState.Disabled
                    spec.FillEnabled =
                        interactionProfile.DisabledFill.Enabled AndAlso
                        themeInteraction.DisabledFill.Enabled

                    spec.RingEnabled = False

                    If spec.FillEnabled Then
                        spec.Fill =
                            ApplyStrength(
                                color:=themeInteraction.DisabledFill.Color,
                                strength:=interactionProfile.DisabledFill.Strength)
                    Else
                        spec.Fill = SKColors.Transparent
                    End If

                    spec.Ring = SKColors.Transparent
                    spec.FillBlendMode = SKBlendMode.SrcOver

                Case Else
                    Throw New NotSupportedException($"Unsupported interaction state: {CInt(normalized)}")

            End Select

            Return spec

        End Function

        Private Shared Function ResolveThemeState(themeInteraction As IMASInteractionTheme,
                                                  state As MASInteractionState,
                                                  intent As MASVisualInteractionIntent) As MASInteractionThemeState

            If themeInteraction Is Nothing Then Throw New ArgumentNullException(NameOf(themeInteraction))

            Select Case intent

                Case MASVisualInteractionIntent.Normal
                    Select Case state
                        Case MASInteractionState.Hovered
                            Return themeInteraction.Hover
                        Case MASInteractionState.Pressed
                            Return themeInteraction.Pressed
                        Case MASInteractionState.Selected
                            Return themeInteraction.Selected
                        Case MASInteractionState.Focused
                            Return themeInteraction.Focused
                        Case Else
                            Return MASInteractionThemeState.None
                    End Select

                Case MASVisualInteractionIntent.Danger
                    Select Case state
                        Case MASInteractionState.Hovered
                            Return themeInteraction.DangerHover
                        Case MASInteractionState.Pressed
                            Return themeInteraction.DangerPressed
                        Case MASInteractionState.Selected
                            Return themeInteraction.DangerSelected
                        Case MASInteractionState.Focused
                            Return themeInteraction.DangerFocused
                        Case Else
                            Return MASInteractionThemeState.None
                    End Select

                Case Else
                    Throw New NotSupportedException($"Unsupported interaction intent: {CInt(intent)}")

            End Select

        End Function

        Private Shared Sub ApplyState(ByRef spec As MASVisualInteractionOverlaySpec,
                                      tuning As InteractionPersonalityProfiles.InteractionStateTuning,
                                      themed As MASInteractionThemeState)

            spec.FillEnabled = tuning.Fill.Enabled AndAlso themed.Fill.Enabled
            spec.RingEnabled = tuning.Ring.Enabled AndAlso themed.Ring.Enabled

            If spec.FillEnabled Then
                spec.Fill = ApplyStrength(themed.Fill.Color, tuning.Fill.Strength)
            Else
                spec.Fill = SKColors.Transparent
            End If

            If spec.RingEnabled Then
                spec.Ring = ApplyStrength(themed.Ring.Color, tuning.Ring.Strength)
            Else
                spec.Ring = SKColors.Transparent
            End If

        End Sub

        Private Shared Sub ApplyGeometryState(ByRef spec As MASVisualInteractionOverlaySpec,
                                              stateProfile As MASVisualInteractionGeometryProfiles.InteractionGeometryStateProfile)

            spec.Shape = stateProfile.Shape
            spec.ExtraFillInsetPx = UnitsToPx(stateProfile.ExtraFillInsetUnits)
            spec.ExtraRingInsetPx = UnitsToPx(stateProfile.ExtraRingInsetUnits)

        End Sub

        Private Shared Function UnitsToPx(units As Single) As Single

            Dim stepPx As Single = SurfaceTokens.FxSnapStepPx

            If Single.IsNaN(stepPx) OrElse
               Single.IsInfinity(stepPx) OrElse
               stepPx <= 0.0F Then

                Throw New InvalidOperationException("Tokens.SurfaceFx.SnapStepPx must be a valid positive value.")
            End If

            If Single.IsNaN(units) OrElse
               Single.IsInfinity(units) OrElse
               units <= 0.0F Then

                Return 0.0F
            End If

            Return units * stepPx

        End Function

#End Region

#Region "Behavior mapping"

        Private Shared Sub ApplyPressedBehavior(ByRef spec As MASVisualInteractionOverlaySpec,
                                                personality As InteractionPersonalityProfiles.InteractionPersonalityProfile)

            If Not spec.FillEnabled Then
                spec.FillBlendMode = SKBlendMode.SrcOver
                Return
            End If

            spec.FillBlendMode = SKBlendMode.Multiply

        End Sub

        Private Shared Sub ApplyHoverBehavior(ByRef spec As MASVisualInteractionOverlaySpec,
                                              personality As InteractionPersonalityProfiles.InteractionPersonalityProfile)

            spec.FillBlendMode = SKBlendMode.SrcOver

        End Sub

        Private Shared Sub ApplySelectedBehavior(ByRef spec As MASVisualInteractionOverlaySpec,
                                                 personality As InteractionPersonalityProfiles.InteractionPersonalityProfile)

            spec.FillBlendMode = SKBlendMode.SrcOver

        End Sub

        Private Shared Sub ApplyFocusedBehavior(ByRef spec As MASVisualInteractionOverlaySpec,
                                                personality As InteractionPersonalityProfiles.InteractionPersonalityProfile)

            spec.FillBlendMode = SKBlendMode.SrcOver

        End Sub

#End Region

#Region "Helpers"

        Private Shared Function ApplyStrength(color As SKColor,
                                              strength As Single) As SKColor

            If Single.IsNaN(strength) OrElse Single.IsInfinity(strength) Then
                Throw New InvalidOperationException("Interaction strength must be finite.")
            End If

            If strength < 0.0F OrElse strength > 1.0F Then
                Throw New InvalidOperationException("Interaction strength must be between 0.0 and 1.0.")
            End If

            Dim sourceAlpha As Integer = CInt(color.Alpha)
            If sourceAlpha <= 0 Then sourceAlpha = 255

            Dim alphaValue As Integer =
                CInt(Math.Round(sourceAlpha * strength))

            If alphaValue < 0 Then alphaValue = 0
            If alphaValue > 255 Then alphaValue = 255

            Return ColorMath.WithAlpha(color, CByte(alphaValue))

        End Function

        Friend Shared Function BuildInputSpec(state As MASInteractionState,
                                              theme As IMASAppTheme,
                                              Optional intent As MASVisualInteractionIntent = MASVisualInteractionIntent.Normal) As MASVisualInteractionOverlaySpec

            Return BuildByKind(
                state:=state,
                kind:=CommonEnums.ControlKind.TextBox,
                theme:=theme,
                intent:=intent)

        End Function

#End Region

    End Class

End Namespace