Option Strict On
Option Explicit On

Imports System
Imports System.Collections.Generic
Imports Nexamas.UI.Components
Imports Nexamas.UI.Controls
Imports Nexamas.UI.Layout
Imports Nexamas.UI.Presentation

Namespace Nexamas.UI.Application

    ''' <summary>
    ''' Official Application settings section for the runtime MAS size profile.
    ''' The section owns only pending UI state. It applies and persists the profile only when Apply is pressed.
    ''' </summary>
    Friend NotInheritable Class MASSizingSettingsSection

        Private Sub New()
        End Sub

        Friend Shared Function Create() As MASSizingSettingsSection
            Return New MASSizingSettingsSection()
        End Function

        Friend Function CreateInstance(window As MASApplicationWindow,
                                       options As MASApplicationSettingsPageOptions) As MASSizingSettingsSectionInstance
            If window Is Nothing Then Throw New ArgumentNullException(NameOf(window))
            Return New MASSizingSettingsSectionInstance(window, MASApplicationSettingsPageOptions.Normalize(options))
        End Function

    End Class

    Friend NotInheritable Class MASSizingSettingsSectionInstance
        Implements IDisposable

        Private Const ProfileIdPrefix As String = "size-profile:"

        Private ReadOnly _window As MASApplicationWindow
        Private ReadOnly _options As MASApplicationSettingsPageOptions
        Private ReadOnly _controls As New List(Of MASControlBase)()
        Private ReadOnly _profileChangedHandler As EventHandler(Of MASSizeProfileChangedEventArgs)

        Private ReadOnly _sectionTitle As MASLabel
        Private ReadOnly _sectionSubtitle As MASLabel
        Private ReadOnly _profilePicker As MASSegmentedControl
        Private ReadOnly _statusLabel As MASLabel
        Private ReadOnly _resetButton As MASButton
        Private ReadOnly _cancelButton As MASButton
        Private ReadOnly _applyButton As MASButton
        Private ReadOnly _previewTitle As MASLabel
        Private ReadOnly _previewText As MASLabel
        Private ReadOnly _previewButton As MASButton
        Private ReadOnly _previewCheckBox As MASCheckBox
        Private ReadOnly _previewProgress As MASProgressBar

        Private _pendingKind As MASSizeProfileKind
        Private _updatingSelection As Boolean
        Private _disposed As Boolean

        Friend Sub New(window As MASApplicationWindow,
                       options As MASApplicationSettingsPageOptions)
            _window = window
            _options = options
            _pendingKind = window.Sizing.CurrentKind

            _sectionTitle = window.Controls.CreateLabel(SafeText(_options.SizingSectionTitle, "Size profile"),
                Sub(label As MASLabel)
                    label.LabelVariant = MASLabelVariant.Heading
                    label.TextRole = MASLabelTextRole.Primary
                End Sub)

            _sectionSubtitle = window.Controls.CreateLabel(SafeText(_options.SizingSectionSubtitle, "Change the runtime MAS size profile."),
                Sub(label As MASLabel)
                    label.LabelVariant = MASLabelVariant.Body
                    label.TextRole = MASLabelTextRole.Secondary
                    label.MultiLine = True
                    label.MaxLines = 3
                End Sub)

            _profilePicker = window.Controls.CreateSegmentedControl(CreateProfileSegments(),
                Sub(control As MASSegmentedControl)
                    control.WithDefaultSize()
                    control.WithSelectedId(ToProfileId(_pendingKind))
                    control.OnSelectedIdChanged(AddressOf OnSelectedProfileIdChanged)
                End Sub)

            _statusLabel = window.Controls.CreateLabel(String.Empty,
                Sub(label As MASLabel)
                    label.LabelVariant = MASLabelVariant.Caption
                    label.TextRole = MASLabelTextRole.Muted
                End Sub)

            _resetButton = window.Controls.CreateButton(SafeText(_options.ResetButtonText, "Reset to Default"),
                Sub(button As MASButton)
                    button.AsSubtle()
                    button.OnClick(AddressOf ResetToDefault)
                End Sub)

            _cancelButton = window.Controls.CreateButton(SafeText(_options.CancelButtonText, "Cancel"),
                Sub(button As MASButton)
                    button.AsSubtle()
                    button.OnClick(AddressOf CancelPendingProfile)
                End Sub)

            _applyButton = window.Controls.CreateButton(SafeText(_options.ApplyButtonText, "Apply"),
                Sub(button As MASButton)
                    button.AsPrimary()
                    button.OnClick(AddressOf ApplyPendingProfile)
                End Sub)

            _controls.Add(_sectionTitle)
            _controls.Add(_sectionSubtitle)
            _controls.Add(_profilePicker)
            _controls.Add(_statusLabel)
            _controls.Add(_resetButton)

            If _options.IncludeActionButtons Then
                _controls.Add(_cancelButton)
                _controls.Add(_applyButton)
            End If

            If _options.IncludePreviewControls Then
                _previewTitle = window.Controls.CreateLabel(SafeText(_options.PreviewTitle, "Preview"),
                    Sub(label As MASLabel)
                        label.LabelVariant = MASLabelVariant.Heading
                        label.TextRole = MASLabelTextRole.Primary
                    End Sub)

                _previewText = window.Controls.CreateLabel(SafeText(_options.PreviewText, "This preview is measured by MASSize and arranged by MASLayout."),
                    Sub(label As MASLabel)
                        label.LabelVariant = MASLabelVariant.Body
                        label.TextRole = MASLabelTextRole.Secondary
                        label.MultiLine = True
                        label.MaxLines = 3
                    End Sub)

                _previewButton = window.Controls.CreateButton("Preview button",
                    Sub(button As MASButton)
                        button.AsPrimary()
                    End Sub)

                _previewCheckBox = window.Controls.CreateCheckBox("Preview checkbox", True)
                _previewProgress = window.Controls.CreateProgressBar(
                    Sub(progress As MASProgressBar)
                        progress.WithPercent(64.0R)
                    End Sub)

                _controls.Add(_previewTitle)
                _controls.Add(_previewText)
                _controls.Add(_previewButton)
                _controls.Add(_previewCheckBox)
                _controls.Add(_previewProgress)
            End If

            UpdateSelectionFromPending()
            UpdateStatusText()

            _profileChangedHandler = AddressOf RuntimeProfileChanged
            AddHandler window.Sizing.CurrentChanged, _profileChangedHandler
        End Sub

        Friend ReadOnly Property Controls As IReadOnlyList(Of MASControlBase)
            Get
                Return _controls.AsReadOnly()
            End Get
        End Property

        Friend Sub AddToPage(presentation As MASPresentationPageBuilder)
            If presentation Is Nothing Then Throw New ArgumentNullException(NameOf(presentation))

            presentation.SectionIntro(_sectionTitle, _sectionSubtitle)

            Dim split As MASApplicationSplitPaneLayoutBuilder = presentation.BeginNarrativeControlInspectionSplit(_statusLabel, Nothing, Nothing)
            split.AddSurface(_profilePicker, MASSize.[Default])
            split.AddSurface(_resetButton, MASApplicationSettingsLayoutPolicy.DefaultActionIntent())

            If _options.IncludePreviewControls AndAlso _previewTitle IsNot Nothing Then
                presentation.SectionIntro(_previewTitle, _previewText)
                split.AddSurface(_previewButton, MASApplicationSettingsLayoutPolicy.DefaultActionIntent())
                split.AddSurface(_previewCheckBox, MASSize.[Default])
                split.AddSurface(_previewProgress, MASSize.[Default])
            End If

            If _options.IncludeActionButtons Then
                presentation.Actions(
                    Sub(actions As MASApplicationActionGroupLayoutBuilder)
                        actions.AlignEnd() _
                               .EqualItemWidth() _
                               .Gap(MASApplicationSettingsLayoutPolicy.ActionGap(_options)) _
                               .Add(_cancelButton, MASApplicationSettingsLayoutPolicy.DefaultActionIntent()) _
                               .Add(_applyButton, MASApplicationSettingsLayoutPolicy.DefaultActionIntent())
                    End Sub)
            End If
        End Sub

        Private Sub OnSelectedProfileIdChanged(selectedId As String)
            If _disposed OrElse _updatingSelection Then Return

            Dim kind As MASSizeProfileKind
            If Not TryParseProfileId(selectedId, kind) Then Return

            _pendingKind = kind
            UpdateStatusText()
        End Sub

        Private Sub ResetToDefault()
            If _disposed Then Return
            _pendingKind = MASSizeProfileKind.[Default]
            UpdateSelectionFromPending()
            UpdateStatusText()
        End Sub

        Private Sub ApplyPendingProfile()
            If _disposed Then Return

            _window.Sizing.ApplyAndSave(_pendingKind)
            _pendingKind = _window.Sizing.CurrentKind
            UpdateSelectionFromPending()
            UpdateStatusText()

            If _options.CloseAfterApply Then
                RequestClose(MASApplicationSettingsCloseReason.Applied)
            End If
        End Sub

        Private Sub CancelPendingProfile()
            If _disposed Then Return

            _pendingKind = _window.Sizing.CurrentKind
            UpdateSelectionFromPending()
            UpdateStatusText()

            If _options.CloseAfterCancel Then
                RequestClose(MASApplicationSettingsCloseReason.Cancel)
            End If
        End Sub

        Private Sub RuntimeProfileChanged(sender As Object, e As MASSizeProfileChangedEventArgs)
            If _disposed Then Return

            Dim hadPendingChanges As Boolean = True
            If e IsNot Nothing Then
                hadPendingChanges = (_pendingKind <> e.OldKind)
            Else
                hadPendingChanges = (_pendingKind <> _window.Sizing.CurrentKind)
            End If

            If Not hadPendingChanges Then
                _pendingKind = _window.Sizing.CurrentKind
                UpdateSelectionFromPending()
            End If

            UpdateStatusText()
        End Sub

        Private Sub UpdateSelectionFromPending()
            If _profilePicker Is Nothing Then Return

            _updatingSelection = True
            Try
                _profilePicker.WithSelectedId(ToProfileId(_pendingKind))
            Finally
                _updatingSelection = False
            End Try
        End Sub

        Private Sub UpdateStatusText()
            If _statusLabel Is Nothing Then Return

            Dim currentKind As MASSizeProfileKind = _window.Sizing.CurrentKind
            If _pendingKind = currentKind Then
                _statusLabel.Text = "Current size profile: " & ToDisplayName(currentKind) & ". No pending changes."
            Else
                _statusLabel.Text = "Selected: " & ToDisplayName(_pendingKind) & ". Press Apply to save. Current: " & ToDisplayName(currentKind) & "."
            End If
        End Sub

        Private Sub RequestClose(reason As MASApplicationSettingsCloseReason)
            Dim closeRequested As Action(Of MASApplicationSettingsCloseReason) = _options.CloseRequested
            If closeRequested Is Nothing Then Return

            Try
                closeRequested.Invoke(reason)
            Catch masCaughtException As Exception
                Nexamas.UI.Diagnostics.MASExceptionSilencer.SwallowBoundary(masCaughtException)
            End Try
        End Sub

        Private Shared Function CreateProfileSegments() As IEnumerable(Of MASSegmentEntry)
            Return New MASSegmentEntry() {
                New MASSegmentEntry(ToProfileId(MASSizeProfileKind.Compact), "Compact"),
                New MASSegmentEntry(ToProfileId(MASSizeProfileKind.[Default]), "Default"),
                New MASSegmentEntry(ToProfileId(MASSizeProfileKind.Comfortable), "Comfortable"),
                New MASSegmentEntry(ToProfileId(MASSizeProfileKind.Large), "Large"),
                New MASSegmentEntry(ToProfileId(MASSizeProfileKind.TouchFriendly), "Touch")
            }
        End Function

        Private Shared Function ToProfileId(kind As MASSizeProfileKind) As String
            Return ProfileIdPrefix & kind.ToString()
        End Function

        Private Shared Function TryParseProfileId(value As String, ByRef kind As MASSizeProfileKind) As Boolean
            kind = MASSizeProfileKind.[Default]

            Dim raw As String = If(value, String.Empty).Trim()
            If raw.Length = 0 Then Return False
            If raw.StartsWith(ProfileIdPrefix, StringComparison.OrdinalIgnoreCase) Then
                raw = raw.Substring(ProfileIdPrefix.Length)
            End If

            Return [Enum].TryParse(Of MASSizeProfileKind)(raw, True, kind)
        End Function

        Private Shared Function ToDisplayName(kind As MASSizeProfileKind) As String
            Select Case kind
                Case MASSizeProfileKind.Compact
                    Return "Compact"
                Case MASSizeProfileKind.Comfortable
                    Return "Comfortable"
                Case MASSizeProfileKind.Large
                    Return "Large"
                Case MASSizeProfileKind.TouchFriendly
                    Return "Touch Friendly"
                Case Else
                    Return "Default"
            End Select
        End Function

        Private Shared Function SafeText(value As String, fallback As String) As String
            Dim result As String = If(value, String.Empty).Trim()
            If result.Length = 0 Then Return If(fallback, String.Empty)
            Return result
        End Function

        Public Sub Dispose() Implements IDisposable.Dispose
            If _disposed Then Return
            _disposed = True
            RemoveHandler _window.Sizing.CurrentChanged, _profileChangedHandler
        End Sub

    End Class

End Namespace
