function Show-MainWindow {    
    Add-Type -AssemblyName PresentationFramework,PresentationCore,WindowsBase,System.Windows.Forms | Out-Null

    # Get current Windows build version
    $WinVersion = Get-ItemPropertyValue 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion' CurrentBuild

    $usesDarkMode = GetSystemUsesDarkMode

    # Load XAML from file
    $xaml = Get-Content -Path $script:MainWindowSchema -Raw
    $reader = [System.Xml.XmlReader]::Create([System.IO.StringReader]::new($xaml))
    try {
        $window = [System.Windows.Markup.XamlReader]::Load($reader)
    }
    finally {
        $reader.Close()
    }

    SetWindowThemeResources -window $window -usesDarkMode $usesDarkMode

    # Get named elements
    $titleBar = $window.FindName('TitleBar')
    $kofiBtn = $window.FindName('KofiBtn')
    $menuBtn = $window.FindName('MenuBtn')
    $closeBtn = $window.FindName('CloseBtn')
    $menuDocumentation = $window.FindName('MenuDocumentation')
    $menuReportBug = $window.FindName('MenuReportBug')
    $menuLogs = $window.FindName('MenuLogs')
    $menuAbout = $window.FindName('MenuAbout')

    # Title bar event handlers
    $titleBar.Add_MouseLeftButtonDown({
        if ($_.OriginalSource -is [System.Windows.Controls.Grid] -or $_.OriginalSource -is [System.Windows.Controls.Border] -or $_.OriginalSource -is [System.Windows.Controls.TextBlock]) {
            $window.DragMove()
        }
    })
    
    $kofiBtn.Add_Click({
        Start-Process "https://ko-fi.com/raphire"
    })
    
    $menuBtn.Add_Click({
        $menuBtn.ContextMenu.PlacementTarget = $menuBtn
        $menuBtn.ContextMenu.Placement = [System.Windows.Controls.Primitives.PlacementMode]::Bottom
        $menuBtn.ContextMenu.IsOpen = $true
    })

    $menuDocumentation.Add_Click({
        Start-Process "https://github.com/Raphire/Win11Debloat/wiki"
    })

    $menuReportBug.Add_Click({
        Start-Process "https://github.com/Raphire/Win11Debloat/issues"
    })

    $menuLogs.Add_Click({
        $logsFolder = Join-Path $PSScriptRoot "../../Logs"
        if (Test-Path $logsFolder) {
            Start-Process "explorer.exe" -ArgumentList $logsFolder
        }
        else {
            Show-MessageBox -Message "No logs folder found at: $logsFolder" -Title "Logs" -Button 'OK' -Icon 'Information'
        }
    })

    $menuAbout.Add_Click({
        Show-AboutDialog -Owner $window
    })

    $closeBtn.Add_Click({
        $window.Close()
    })

    # Ensure closing the main window stops all execution
    $window.Add_Closing({
        $script:CancelRequested = $true
    })

    # Implement window resize functionality
    $resizeLeft = $window.FindName('ResizeLeft')
    $resizeRight = $window.FindName('ResizeRight')
    $resizeTop = $window.FindName('ResizeTop')
    $resizeBottom = $window.FindName('ResizeBottom')
    $resizeTopLeft = $window.FindName('ResizeTopLeft')
    $resizeTopRight = $window.FindName('ResizeTopRight')
    $resizeBottomLeft = $window.FindName('ResizeBottomLeft')
    $resizeBottomRight = $window.FindName('ResizeBottomRight')

    $script:resizing = $false
    $script:resizeEdges = $null
    $script:resizeStart = $null
    $script:windowStart = $null
    $script:resizeElement = $null

    $resizeHandler = {
        param($sender, $e)
        
        $script:resizing = $true
        $script:resizeElement = $sender
        $script:resizeStart = [System.Windows.Forms.Cursor]::Position
        $script:windowStart = @{
            Left = $window.Left
            Top = $window.Top
            Width = $window.ActualWidth
            Height = $window.ActualHeight
        }
        
        # Parse direction tag into edge flags for cleaner resize logic
        $direction = $sender.Tag
        $script:resizeEdges = @{
            Left = $direction -match 'Left'
            Right = $direction -match 'Right'
            Top = $direction -match 'Top'
            Bottom = $direction -match 'Bottom'
        }
        
        $sender.CaptureMouse()
        $e.Handled = $true
    }

    $moveHandler = {
        param($sender, $e)
        if (-not $script:resizing) { return }
        
        $current = [System.Windows.Forms.Cursor]::Position
        $deltaX = $current.X - $script:resizeStart.X
        $deltaY = $current.Y - $script:resizeStart.Y

        # Handle horizontal resize
        if ($script:resizeEdges.Left) {
            $newWidth = [Math]::Max($window.MinWidth, $script:windowStart.Width - $deltaX)
            if ($newWidth -ne $window.Width) {
                $window.Left = $script:windowStart.Left + ($script:windowStart.Width - $newWidth)
                $window.Width = $newWidth
            }
        }
        elseif ($script:resizeEdges.Right) {
            $window.Width = [Math]::Max($window.MinWidth, $script:windowStart.Width + $deltaX)
        }

        # Handle vertical resize
        if ($script:resizeEdges.Top) {
            $newHeight = [Math]::Max($window.MinHeight, $script:windowStart.Height - $deltaY)
            if ($newHeight -ne $window.Height) {
                $window.Top = $script:windowStart.Top + ($script:windowStart.Height - $newHeight)
                $window.Height = $newHeight
            }
        }
        elseif ($script:resizeEdges.Bottom) {
            $window.Height = [Math]::Max($window.MinHeight, $script:windowStart.Height + $deltaY)
        }
        
        $e.Handled = $true
    }

    $releaseHandler = {
        param($sender, $e)
        if ($script:resizing -and $script:resizeElement) {
            $script:resizing = $false
            $script:resizeEdges = $null
            $script:resizeElement.ReleaseMouseCapture()
            $script:resizeElement = $null
            $e.Handled = $true
        }
    }

    # Set tags and add event handlers for resize borders
    $resizeLeft.Tag = 'Left'
    $resizeLeft.Add_PreviewMouseLeftButtonDown($resizeHandler)
    $resizeLeft.Add_MouseMove($moveHandler)
    $resizeLeft.Add_MouseLeftButtonUp($releaseHandler)
    
    $resizeRight.Tag = 'Right'
    $resizeRight.Add_PreviewMouseLeftButtonDown($resizeHandler)
    $resizeRight.Add_MouseMove($moveHandler)
    $resizeRight.Add_MouseLeftButtonUp($releaseHandler)
    
    $resizeTop.Tag = 'Top'
    $resizeTop.Add_PreviewMouseLeftButtonDown($resizeHandler)
    $resizeTop.Add_MouseMove($moveHandler)
    $resizeTop.Add_MouseLeftButtonUp($releaseHandler)
    
    $resizeBottom.Tag = 'Bottom'
    $resizeBottom.Add_PreviewMouseLeftButtonDown($resizeHandler)
    $resizeBottom.Add_MouseMove($moveHandler)
    $resizeBottom.Add_MouseLeftButtonUp($releaseHandler)
    
    $resizeTopLeft.Tag = 'TopLeft'
    $resizeTopLeft.Add_PreviewMouseLeftButtonDown($resizeHandler)
    $resizeTopLeft.Add_MouseMove($moveHandler)
    $resizeTopLeft.Add_MouseLeftButtonUp($releaseHandler)
    
    $resizeTopRight.Tag = 'TopRight'
    $resizeTopRight.Add_PreviewMouseLeftButtonDown($resizeHandler)
    $resizeTopRight.Add_MouseMove($moveHandler)
    $resizeTopRight.Add_MouseLeftButtonUp($releaseHandler)
    
    $resizeBottomLeft.Tag = 'BottomLeft'
    $resizeBottomLeft.Add_PreviewMouseLeftButtonDown($resizeHandler)
    $resizeBottomLeft.Add_MouseMove($moveHandler)
    $resizeBottomLeft.Add_MouseLeftButtonUp($releaseHandler)
    
    $resizeBottomRight.Tag = 'BottomRight'
    $resizeBottomRight.Add_PreviewMouseLeftButtonDown($resizeHandler)
    $resizeBottomRight.Add_MouseMove($moveHandler)
    $resizeBottomRight.Add_MouseLeftButtonUp($releaseHandler)

    # Integrated App Selection UI
    $appsPanel = $window.FindName('AppSelectionPanel')
    $onlyInstalledAppsBox = $window.FindName('OnlyInstalledAppsBox')
    $loadingAppsIndicator = $window.FindName('LoadingAppsIndicator')
    $appSelectionStatus = $window.FindName('AppSelectionStatus')
    $defaultAppsBtn = $window.FindName('DefaultAppsBtn')
    $clearAppSelectionBtn = $window.FindName('ClearAppSelectionBtn')
    
    # Track the last selected checkbox for shift-click range selection
    $script:MainWindowLastSelectedCheckbox = $null
    
    # Track current app loading operation to prevent race conditions
    $script:CurrentAppLoadTimer = $null
    $script:CurrentAppLoadJob = $null
    $script:CurrentAppLoadJobStartTime = $null
    
    # Set script-level variable for GUI window reference
    $script:GuiWindow = $window

    # Updates app selection status text in the App Selection tab
    function UpdateAppSelectionStatus {
        $selectedCount = 0
        foreach ($child in $appsPanel.Children) {
            if ($child -is [System.Windows.Controls.CheckBox] -and $child.IsChecked) {
                $selectedCount++
            }
        }
        $appSelectionStatus.Text = "$selectedCount app(s) selected for removal"
    }

    # Dynamically builds Tweaks UI from Features.json
    function BuildDynamicTweaks {
        $featuresJson = LoadJsonFile -filePath $script:FeaturesFilePath -expectedVersion "1.0"

        if (-not $featuresJson) {
            Show-MessageBox -Message "Unable to load Features.json file!" -Title "Error" -Button 'OK' -Icon 'Error' | Out-Null
            Exit
        }

        # Column containers
        $col0 = $window.FindName('Column0Panel')
        $col1 = $window.FindName('Column1Panel')
        $col2 = $window.FindName('Column2Panel')
        $columns = @($col0, $col1, $col2) | Where-Object { $_ -ne $null }

        # Clear all columns for fully dynamic panel creation
        foreach ($col in $columns) {
            if ($col) { $col.Children.Clear() }
        }

        $script:UiControlMappings = @{}
        $script:CategoryCardMap = @{}

        function CreateLabeledCombo($parent, $labelText, $comboName, $items) {
            # If only 2 items (No Change + one option), use a checkbox instead
            if ($items.Count -eq 2) {
                $checkbox = New-Object System.Windows.Controls.CheckBox
                $checkbox.Content = $labelText
                $checkbox.Name = $comboName
                $checkbox.SetValue([System.Windows.Automation.AutomationProperties]::NameProperty, $labelText)
                $checkbox.IsChecked = $false
                $checkbox.Style = $window.Resources["FeatureCheckboxStyle"]
                $parent.Children.Add($checkbox) | Out-Null
                
                # Register the checkbox with the window's name scope
                try {
                    [System.Windows.NameScope]::SetNameScope($checkbox, [System.Windows.NameScope]::GetNameScope($window))
                    $window.RegisterName($comboName, $checkbox)
                }
                catch {
                    # Name might already be registered, ignore
                }
                
                return $checkbox
            }
            
            # Otherwise use a combobox for multiple options
            # Wrap label in a Border for search highlighting
            $lblBorder = New-Object System.Windows.Controls.Border
            $lblBorder.Style = $window.Resources['LabelBorderStyle']
            $lblBorderName = "$comboName`_LabelBorder"
            $lblBorder.Name = $lblBorderName
            
            $lbl = New-Object System.Windows.Controls.TextBlock
            $lbl.Text = $labelText
            $lbl.Style = $window.Resources['LabelStyle']
            $labelName = "$comboName`_Label"
            $lbl.Name = $labelName
            
            $lblBorder.Child = $lbl
            $parent.Children.Add($lblBorder) | Out-Null
            
            # Register the label border with the window's name scope
            try {
                [System.Windows.NameScope]::SetNameScope($lblBorder, [System.Windows.NameScope]::GetNameScope($window))
                $window.RegisterName($lblBorderName, $lblBorder)
            }
            catch {
                # Name might already be registered, ignore
            }

            $combo = New-Object System.Windows.Controls.ComboBox
            $combo.Name = $comboName
            $combo.SetValue([System.Windows.Automation.AutomationProperties]::NameProperty, $labelText)
            foreach ($it in $items) { $cbItem = New-Object System.Windows.Controls.ComboBoxItem; $cbItem.Content = $it; $combo.Items.Add($cbItem) | Out-Null }
            $combo.SelectedIndex = 0
            $parent.Children.Add($combo) | Out-Null
            
            # Register the combo box with the window's name scope
            try {
                [System.Windows.NameScope]::SetNameScope($combo, [System.Windows.NameScope]::GetNameScope($window))
                $window.RegisterName($comboName, $combo)
            }
            catch {
                # Name might already be registered, ignore
            }
            
            return $combo
        }

        function GetWikiUrlForCategory($category) {
            if (-not $category) { return 'https://github.com/Raphire/Win11Debloat/wiki/Features' }

            $slug = $category.ToLowerInvariant()
            $slug = $slug -replace '&', ''
            $slug = $slug -replace '[^a-z0-9\s-]', ''
            $slug = $slug -replace '\s', '-'

            return "https://github.com/Raphire/Win11Debloat/wiki/Features#$slug"
        }

        function GetOrCreateCategoryCard($categoryObj) {
            $categoryName = $categoryObj.Name
            $categoryIcon = $categoryObj.Icon

            if ($script:CategoryCardMap.ContainsKey($categoryName)) { return $script:CategoryCardMap[$categoryName] }

            # Create a new card Border + StackPanel and add to shortest column
            $target = $columns | Sort-Object @{Expression={$_.Children.Count}; Ascending=$true}, @{Expression={$columns.IndexOf($_)}; Ascending=$true} | Select-Object -First 1

            $border = New-Object System.Windows.Controls.Border
            $border.Style = $window.Resources['CategoryCardBorderStyle']
            $border.Tag = 'DynamicCategory'

            $panel = New-Object System.Windows.Controls.StackPanel
            $safe = ($categoryName -replace '[^a-zA-Z0-9_]','_')
            $panel.Name = "Category_{0}_Panel" -f $safe

            $headerRow = New-Object System.Windows.Controls.StackPanel
            $headerRow.Orientation = 'Horizontal'

            # Add category icon
            $icon = New-Object System.Windows.Controls.TextBlock
            # Convert HTML entity to character (e.g., &#xE72E; -> actual character)
            if ($categoryIcon -match '&#x([0-9A-Fa-f]+);') {
                $hexValue = [Convert]::ToInt32($matches[1], 16)
                $icon.Text = [char]$hexValue
            }
            $icon.Style = $window.Resources['CategoryHeaderIcon']
            $headerRow.Children.Add($icon) | Out-Null

            $header = New-Object System.Windows.Controls.TextBlock
            $header.Text = $categoryName
            $header.Style = $window.Resources['CategoryHeaderTextBlock']
            $headerRow.Children.Add($header) | Out-Null

            $helpIcon = New-Object System.Windows.Controls.TextBlock
            $helpIcon.Text = '(?)'
            $helpIcon.Style = $window.Resources['CategoryHelpLinkTextStyle']

            $helpBtn = New-Object System.Windows.Controls.Button
            $helpBtn.Content = $helpIcon
            $helpBtn.ToolTip = "Open wiki for more info on '$categoryName' tweaks"
            $helpBtn.Tag = (GetWikiUrlForCategory -category $categoryName)
            $helpBtn.Style = $window.Resources['CategoryHelpLinkButtonStyle']
            $helpBtn.Add_Click({
                param($sender, $e)
                if ($sender.Tag) { Start-Process $sender.Tag }
            })
            $headerRow.Children.Add($helpBtn) | Out-Null

            $panel.Children.Add($headerRow) | Out-Null

            $border.Child = $panel
            $target.Children.Add($border) | Out-Null

            $script:CategoryCardMap[$categoryName] = $panel
            return $panel
        }

        # Determine categories present (from lists and features)
        $categoriesPresent = @{}
        if ($featuresJson.UiGroups) {
            foreach ($g in $featuresJson.UiGroups) { if ($g.Category) { $categoriesPresent[$g.Category] = $true } }
        }
        foreach ($f in $featuresJson.Features) { if ($f.Category) { $categoriesPresent[$f.Category] = $true } }

        # Create cards in the order defined in Features.json Categories (if present)
        $orderedCategories = @()
        if ($featuresJson.Categories) {
            foreach ($c in $featuresJson.Categories) {
                $categoryName = if ($c -is [string]) { $c } else { $c.Name }
                if ($categoriesPresent.ContainsKey($categoryName)) {
                    # Store the full category object (or create one with default icon for string categories)
                    $categoryObj = if ($c -is [string]) { @{Name = $c; Icon = '&#xE712;'} } else { $c }
                    $orderedCategories += $categoryObj
                }
            }
        } else {
            # For backward compatibility, create category objects from keys
            foreach ($catName in $categoriesPresent.Keys) {
                $orderedCategories += @{Name = $catName; Icon = '&#xE712;'}
            }
        }

        foreach ($categoryObj in $orderedCategories) {
            $categoryName = $categoryObj.Name
            
            # Create/get card for this category
            $panel = GetOrCreateCategoryCard -categoryObj $categoryObj
            if (-not $panel) { continue }

            # Collect groups and features for this category, then sort by priority
            $categoryItems = @()

            # Add any groups for this category
            if ($featuresJson.UiGroups) {
                $groupIndex = 0
                foreach ($group in $featuresJson.UiGroups) {
                    if ($group.Category -ne $categoryName) { $groupIndex++; continue }
                    $categoryItems += [PSCustomObject]@{
                        Type = 'group'
                        Data = $group
                        Priority = if ($null -ne $group.Priority) { $group.Priority } else { [int]::MaxValue }
                        OriginalIndex = $groupIndex
                    }
                    $groupIndex++
                }
            }

            # Add individual features for this category
            $featureIndex = 0
            foreach ($feature in $featuresJson.Features) {
                if ($feature.Category -ne $categoryName) { $featureIndex++; continue }
                
                # Check version and feature compatibility using Features.json
                if (($feature.MinVersion -and $WinVersion -lt $feature.MinVersion) -or ($feature.MaxVersion -and $WinVersion -gt $feature.MaxVersion) -or ($feature.FeatureId -eq 'DisableModernStandbyNetworking' -and (-not $script:ModernStandbySupported))) {
                    $featureIndex++; continue
                }

                # Skip if feature part of a group
                $inGroup = $false
                if ($featuresJson.UiGroups) {
                    foreach ($g in $featuresJson.UiGroups) { foreach ($val in $g.Values) { if ($val.FeatureIds -contains $feature.FeatureId) { $inGroup = $true; break } }; if ($inGroup) { break } }
                }
                if ($inGroup) { $featureIndex++; continue }

                $categoryItems += [PSCustomObject]@{
                    Type = 'feature'
                    Data = $feature
                    Priority = if ($null -ne $feature.Priority) { $feature.Priority } else { [int]::MaxValue }
                    OriginalIndex = $featureIndex
                }
                $featureIndex++
            }

            # Sort by priority first, then by original index for items with same/no priority
            $sortedItems = $categoryItems | Sort-Object -Property Priority, OriginalIndex

            # Render sorted items
            foreach ($item in $sortedItems) {
                if ($item.Type -eq 'group') {
                    $group = $item.Data
                    $items = @('No Change') + ($group.Values | ForEach-Object { $_.Label })
                    $comboName = 'Group_{0}Combo' -f $group.GroupId
                    $combo = CreateLabeledCombo -parent $panel -labelText $group.Label -comboName $comboName -items $items
                    # attach tooltip from UiGroups if present
                    if ($group.ToolTip) {
                        $tipBlock = New-Object System.Windows.Controls.TextBlock
                        $tipBlock.Text = $group.ToolTip
                        $tipBlock.TextWrapping = 'Wrap'
                        $tipBlock.MaxWidth = 420
                        $combo.ToolTip = $tipBlock
                        $lblBorderObj = $null
                        try { $lblBorderObj = $window.FindName("$comboName`_LabelBorder") } catch {}
                        if ($lblBorderObj) { $lblBorderObj.ToolTip = $tipBlock }
                    }
                    $script:UiControlMappings[$comboName] = @{ Type='group'; Values = $group.Values; Label = $group.Label }
                }
                elseif ($item.Type -eq 'feature') {
                    $feature = $item.Data
                    $opt = 'Apply'
                    if ($feature.FeatureId -match '^Disable') { $opt = 'Disable' } elseif ($feature.FeatureId -match '^Enable') { $opt = 'Enable' }
                    $items = @('No Change', $opt)
                    $comboName = ("Feature_{0}_Combo" -f $feature.FeatureId) -replace '[^a-zA-Z0-9_]',''
                    $combo = CreateLabeledCombo -parent $panel -labelText ($feature.Action + ' ' + $feature.Label) -comboName $comboName -items $items
                    # attach tooltip from Features.json if present
                    if ($feature.ToolTip) {
                        $tipBlock = New-Object System.Windows.Controls.TextBlock
                        $tipBlock.Text = $feature.ToolTip
                        $tipBlock.TextWrapping = 'Wrap'
                        $tipBlock.MaxWidth = 420
                        $combo.ToolTip = $tipBlock
                        $lblBorderObj = $null
                        try { $lblBorderObj = $window.FindName("$comboName`_LabelBorder") } catch {}
                        if ($lblBorderObj) { $lblBorderObj.ToolTip = $tipBlock }
                    }
                    $script:UiControlMappings[$comboName] = @{ Type='feature'; FeatureId = $feature.FeatureId; Action = $feature.Action }
                }
            }
        }
    }

    # Helper function to complete app loading with the WinGet list
    function script:LoadAppsWithList($listOfApps) {
        $appsToAdd = LoadAppsDetailsFromJson -OnlyInstalled:$onlyInstalledAppsBox.IsChecked -InstalledList $listOfApps -InitialCheckedFromJson:$false

        # Reset the last selected checkbox when loading a new list
        $script:MainWindowLastSelectedCheckbox = $null

        # Sort apps alphabetically and add to panel
        $appsToAdd | Sort-Object -Property FriendlyName | ForEach-Object {
            $checkbox = New-Object System.Windows.Controls.CheckBox
            $checkbox.SetValue([System.Windows.Automation.AutomationProperties]::NameProperty, $_.FriendlyName)
            $checkbox.Tag = $_.AppId
            $checkbox.IsChecked = $_.IsChecked
            $checkbox.Style = $window.Resources["AppsPanelCheckBoxStyle"]

            # Build table row content: App Name | Description | App ID
            $row = New-Object System.Windows.Controls.Grid
            $c0 = New-Object System.Windows.Controls.ColumnDefinition; $c0.Width = [System.Windows.GridLength]::new(160)
            $c1 = New-Object System.Windows.Controls.ColumnDefinition; $c1.Width = [System.Windows.GridLength]::new(1, [System.Windows.GridUnitType]::Star)
            $c2 = New-Object System.Windows.Controls.ColumnDefinition; $c2.Width = [System.Windows.GridLength]::new(286)
            $row.ColumnDefinitions.Add($c0); $row.ColumnDefinitions.Add($c1); $row.ColumnDefinitions.Add($c2)

            $tbName = New-Object System.Windows.Controls.TextBlock
            $tbName.Text = $_.FriendlyName
            $tbName.Style = $window.Resources["AppNameTextStyle"]
            [System.Windows.Controls.Grid]::SetColumn($tbName, 0)

            $tbDesc = New-Object System.Windows.Controls.TextBlock
            $tbDesc.Text = $_.Description
            $tbDesc.Style = $window.Resources["AppDescTextStyle"]
            $tbDesc.ToolTip = $_.Description
            [System.Windows.Controls.Grid]::SetColumn($tbDesc, 1)

            $tbId = New-Object System.Windows.Controls.TextBlock
            $tbId.Text = $_.AppId
            $tbId.Style = $window.Resources["AppIdTextStyle"]
            $tbId.ToolTip = $_.AppId
            [System.Windows.Controls.Grid]::SetColumn($tbId, 2)

            $row.Children.Add($tbName) | Out-Null
            $row.Children.Add($tbDesc) | Out-Null
            $row.Children.Add($tbId) | Out-Null
            $checkbox.Content = $row

            # Store metadata in checkbox for later use
            Add-Member -InputObject $checkbox -MemberType NoteProperty -Name "AppName" -Value $_.FriendlyName
            Add-Member -InputObject $checkbox -MemberType NoteProperty -Name "AppDescription" -Value $_.Description
            Add-Member -InputObject $checkbox -MemberType NoteProperty -Name "SelectedByDefault" -Value $_.SelectedByDefault
            
            # Add event handler to update status
            $checkbox.Add_Checked({ UpdateAppSelectionStatus })
            $checkbox.Add_Unchecked({ UpdateAppSelectionStatus })
            
            # Attach shift-click behavior for range selection
            AttachShiftClickBehavior -checkbox $checkbox -appsPanel $appsPanel -lastSelectedCheckboxRef ([ref]$script:MainWindowLastSelectedCheckbox) -updateStatusCallback { UpdateAppSelectionStatus }
            
            $appsPanel.Children.Add($checkbox) | Out-Null
        }

        # Hide loading indicator and navigation blocker, update status
        $loadingAppsIndicator.Visibility = 'Collapsed'

        UpdateAppSelectionStatus
    }

    # Loads apps into the UI
    function LoadAppsIntoMainUI {
        # Cancel any existing load operation to prevent race conditions
        if ($script:CurrentAppLoadTimer -and $script:CurrentAppLoadTimer.IsEnabled) {
            $script:CurrentAppLoadTimer.Stop()
        }
        if ($script:CurrentAppLoadJob) {
            Remove-Job -Job $script:CurrentAppLoadJob -Force -ErrorAction SilentlyContinue
        }
        $script:CurrentAppLoadTimer = $null
        $script:CurrentAppLoadJob = $null
        $script:CurrentAppLoadJobStartTime = $null
        
        # Show loading indicator and navigation blocker, clear existing apps immediately
        $loadingAppsIndicator.Visibility = 'Visible'
        $appsPanel.Children.Clear()
        
        # Update navigation buttons to disable Next/Previous
        UpdateNavigationButtons
        
        # Force UI to update and render all changes (loading indicator, blocker, disabled buttons)
        $window.Dispatcher.Invoke([System.Windows.Threading.DispatcherPriority]::Render, [action]{})
        
        # Schedule the actual loading work to run after UI has updated
        $window.Dispatcher.BeginInvoke([System.Windows.Threading.DispatcherPriority]::Background, [action]{
            $listOfApps = ""

            if ($onlyInstalledAppsBox.IsChecked -and ($script:WingetInstalled -eq $true)) {
                # Start job to get list of installed apps via WinGet (async helper)
                $asyncJob = GetInstalledAppsViaWinget -Async
                $script:CurrentAppLoadJob = $asyncJob.Job
                $script:CurrentAppLoadJobStartTime = $asyncJob.StartTime
                
                # Create timer to poll job status without blocking UI
                $script:CurrentAppLoadTimer = New-Object System.Windows.Threading.DispatcherTimer
                $script:CurrentAppLoadTimer.Interval = [TimeSpan]::FromMilliseconds(100)
                
                $script:CurrentAppLoadTimer.Add_Tick({
                    # Check if this timer was cancelled (another load started)
                    if (-not $script:CurrentAppLoadJob -or -not $script:CurrentAppLoadTimer -or -not $script:CurrentAppLoadJobStartTime) {
                        if ($script:CurrentAppLoadTimer) { $script:CurrentAppLoadTimer.Stop() }
                        return
                    }
                    
                    $elapsed = (Get-Date) - $script:CurrentAppLoadJobStartTime
                    
                    # Check if job is complete or timed out (10 seconds)
                    if ($script:CurrentAppLoadJob.State -eq 'Completed') {
                        $script:CurrentAppLoadTimer.Stop()
                        $listOfApps = Receive-Job -Job $script:CurrentAppLoadJob
                        Remove-Job -Job $script:CurrentAppLoadJob -ErrorAction SilentlyContinue
                        $script:CurrentAppLoadJob = $null
                        $script:CurrentAppLoadTimer = $null
                        $script:CurrentAppLoadJobStartTime = $null
                        
                        # Continue with loading apps
                        LoadAppsWithList $listOfApps
                    }
                    elseif ($elapsed.TotalSeconds -gt 10 -or $script:CurrentAppLoadJob.State -eq 'Failed') {
                        $script:CurrentAppLoadTimer.Stop()
                        Remove-Job -Job $script:CurrentAppLoadJob -Force -ErrorAction SilentlyContinue
                        $script:CurrentAppLoadJob = $null
                        $script:CurrentAppLoadTimer = $null
                        $script:CurrentAppLoadJobStartTime = $null
                        
                        # Show error that the script was unable to get list of apps from WinGet
                        Show-MessageBox -Message 'Unable to load list of installed apps via WinGet.' -Title 'Error' -Button 'OK' -Icon 'Error' | Out-Null
                        $onlyInstalledAppsBox.IsChecked = $false
                        
                        # Continue with loading all apps (unchecked now)
                        LoadAppsWithList ""
                    }
                })
                
                $script:CurrentAppLoadTimer.Start()
                return  # Exit here, timer will continue the work
            }

            # If checkbox is not checked or winget not installed, load all apps immediately
            LoadAppsWithList $listOfApps
        }) | Out-Null
    }

    # Event handlers for app selection
    $onlyInstalledAppsBox.Add_Checked({
        LoadAppsIntoMainUI 
    })
    $onlyInstalledAppsBox.Add_Unchecked({
        LoadAppsIntoMainUI 
    })

    # Quick selection buttons - only select apps actually in those categories
    $defaultAppsBtn.Add_Click({
        foreach ($child in $appsPanel.Children) {
            if ($child -is [System.Windows.Controls.CheckBox]) {
                if ($child.SelectedByDefault -eq $true) {
                    $child.IsChecked = $true
                } else {
                    $child.IsChecked = $false
                }
            }
        }
    })

    $clearAppSelectionBtn.Add_Click({
        foreach ($child in $appsPanel.Children) {
            if ($child -is [System.Windows.Controls.CheckBox]) {
                $child.IsChecked = $false
            }
        }
    })

    # Helper function to scroll to an item if it's not visible, centering it in the viewport
    function ScrollToItemIfNotVisible {
        param (
            [System.Windows.Controls.ScrollViewer]$scrollViewer,
            [System.Windows.UIElement]$item,
            [System.Windows.UIElement]$container
        )
        
        if (-not $scrollViewer -or -not $item -or -not $container) { return }
        
        try {
            $itemPosition = $item.TransformToAncestor($container).Transform([System.Windows.Point]::new(0, 0)).Y
            $viewportHeight = $scrollViewer.ViewportHeight
            $itemHeight = $item.ActualHeight
            $currentOffset = $scrollViewer.VerticalOffset
            
            # Check if the item is currently visible in the viewport
            $itemTop = $itemPosition - $currentOffset
            $itemBottom = $itemTop + $itemHeight
            
            $isVisible = ($itemTop -ge 0) -and ($itemBottom -le $viewportHeight)
            
            # Only scroll if the item is not visible
            if (-not $isVisible) {
                # Center the item in the viewport
                $targetOffset = $itemPosition - ($viewportHeight / 2) + ($itemHeight / 2)
                $scrollViewer.ScrollToVerticalOffset([Math]::Max(0, $targetOffset))
            }
        }
        catch {
            # Fallback to simple bring into view
            $item.BringIntoView()
        }
    }
    
    # Helper function to find the parent ScrollViewer of an element
    function FindParentScrollViewer {
        param ([System.Windows.UIElement]$element)
        
        $parent = [System.Windows.Media.VisualTreeHelper]::GetParent($element)
        while ($null -ne $parent) {
            if ($parent -is [System.Windows.Controls.ScrollViewer]) {
                return $parent
            }
            $parent = [System.Windows.Media.VisualTreeHelper]::GetParent($parent)
        }
        return $null
    }

    # App Search Box functionality
    $appSearchBox = $window.FindName('AppSearchBox')
    $appSearchPlaceholder = $window.FindName('AppSearchPlaceholder')
    
    # Track current search matches and active index for Enter-key navigation
    $script:AppSearchMatches = @()
    $script:AppSearchMatchIndex = -1
    
    $appSearchBox.Add_TextChanged({
        $searchText = $appSearchBox.Text.ToLower().Trim()
        
        # Show/hide placeholder
        $appSearchPlaceholder.Visibility = if ([string]::IsNullOrWhiteSpace($appSearchBox.Text)) { 'Visible' } else { 'Collapsed' }
        
        # Clear all highlights first
        foreach ($child in $appsPanel.Children) {
            if ($child -is [System.Windows.Controls.CheckBox]) {
                $child.Background = [System.Windows.Media.Brushes]::Transparent
            }
        }
        
        $script:AppSearchMatches = @()
        $script:AppSearchMatchIndex = -1
        
        if ([string]::IsNullOrWhiteSpace($searchText)) { return }
        
        # Find and highlight all matching apps
        $highlightBrush = $window.Resources["SearchHighlightColor"]
        $activeHighlightBrush = $window.Resources["SearchHighlightActiveColor"]
        
        foreach ($child in $appsPanel.Children) {
            if ($child -is [System.Windows.Controls.CheckBox] -and $child.Visibility -eq 'Visible') {
                $appName = if ($child.AppName) { $child.AppName } else { '' }
                $appId = if ($child.Tag) { $child.Tag.ToString() } else { '' }
                $appDesc = if ($child.AppDescription) { $child.AppDescription } else { '' }
                if ($appName.ToLower().Contains($searchText) -or $appId.ToLower().Contains($searchText) -or $appDesc.ToLower().Contains($searchText)) {
                    $child.Background = $highlightBrush
                    $script:AppSearchMatches += $child
                }
            }
        }
        
        # Scroll to first match and mark it as active
        if ($script:AppSearchMatches.Count -gt 0) {
            $script:AppSearchMatchIndex = 0
            $script:AppSearchMatches[0].Background = $activeHighlightBrush
            $scrollViewer = FindParentScrollViewer -element $appsPanel
            if ($scrollViewer) {
                ScrollToItemIfNotVisible -scrollViewer $scrollViewer -item $script:AppSearchMatches[0] -container $appsPanel
            }
        }
    })
    
    $appSearchBox.Add_KeyDown({
        param($sender, $e)
        if ($e.Key -eq [System.Windows.Input.Key]::Enter -and $script:AppSearchMatches.Count -gt 0) {
            # Reset background of current active match
            $script:AppSearchMatches[$script:AppSearchMatchIndex].Background = $window.Resources["SearchHighlightColor"]
            # Advance to next match (wrapping)
            $script:AppSearchMatchIndex = ($script:AppSearchMatchIndex + 1) % $script:AppSearchMatches.Count
            # Highlight new active match
            $script:AppSearchMatches[$script:AppSearchMatchIndex].Background = $window.Resources["SearchHighlightActiveColor"]
            $scrollViewer = FindParentScrollViewer -element $appsPanel
            if ($scrollViewer) {
                ScrollToItemIfNotVisible -scrollViewer $scrollViewer -item $script:AppSearchMatches[$script:AppSearchMatchIndex] -container $appsPanel
            }
            $e.Handled = $true
        }
    })

    # Tweak Search Box functionality
    $tweakSearchBox = $window.FindName('TweakSearchBox')
    $tweakSearchPlaceholder = $window.FindName('TweakSearchPlaceholder')
    $tweakSearchBorder = $window.FindName('TweakSearchBorder')
    $tweaksScrollViewer = $window.FindName('TweaksScrollViewer')
    $tweaksGrid = $window.FindName('TweaksGrid')
    $col0 = $window.FindName('Column0Panel')
    $col1 = $window.FindName('Column1Panel')
    $col2 = $window.FindName('Column2Panel')
    
    # Monitor scrollbar visibility and adjust searchbar margin
    $tweaksScrollViewer.Add_ScrollChanged({
        if ($tweaksScrollViewer.ScrollableHeight -gt 0) {
            # The 17px accounts for the scrollbar width + some padding
            $tweakSearchBorder.Margin = [System.Windows.Thickness]::new(0, 0, 17, 0)
        } else {
            $tweakSearchBorder.Margin = [System.Windows.Thickness]::new(0, 0, 0, 0)
        }
    })
    
    # Helper function to clear all tweak highlights
    function ClearTweakHighlights {
        $columns = @($col0, $col1, $col2) | Where-Object { $_ -ne $null }
        foreach ($column in $columns) {
            foreach ($card in $column.Children) {
                if ($card -is [System.Windows.Controls.Border] -and $card.Child -is [System.Windows.Controls.StackPanel]) {
                    foreach ($control in $card.Child.Children) {
                        if ($control -is [System.Windows.Controls.CheckBox] -or 
                            ($control -is [System.Windows.Controls.Border] -and $control.Name -like '*_LabelBorder')) {
                            $control.Background = [System.Windows.Media.Brushes]::Transparent
                        }
                    }
                }
            }
        }
    }
    
    # Helper function to check if a ComboBox contains matching items
    function ComboBoxContainsMatch {
        param ([System.Windows.Controls.ComboBox]$comboBox, [string]$searchText)
        
        foreach ($item in $comboBox.Items) {
            $itemText = if ($item -is [System.Windows.Controls.ComboBoxItem]) { $item.Content.ToString().ToLower() } else { $item.ToString().ToLower() }
            if ($itemText.Contains($searchText)) { return $true }
        }
        return $false
    }
    
    $tweakSearchBox.Add_TextChanged({
        $searchText = $tweakSearchBox.Text.ToLower().Trim()
        
        # Show/hide placeholder
        $tweakSearchPlaceholder.Visibility = if ([string]::IsNullOrWhiteSpace($tweakSearchBox.Text)) { 'Visible' } else { 'Collapsed' }
        
        # Clear all highlights
        ClearTweakHighlights
        
        if ([string]::IsNullOrWhiteSpace($searchText)) { return }
        
        # Find and highlight all matching tweaks
        $firstMatch = $null
        $highlightBrush = $window.Resources["SearchHighlightColor"]
        $columns = @($col0, $col1, $col2) | Where-Object { $_ -ne $null }
        
        foreach ($column in $columns) {
            foreach ($card in $column.Children) {
                if ($card -is [System.Windows.Controls.Border] -and $card.Child -is [System.Windows.Controls.StackPanel]) {
                    $controlsList = @($card.Child.Children)
                    for ($i = 0; $i -lt $controlsList.Count; $i++) {
                        $control = $controlsList[$i]
                        $matchFound = $false
                        $controlToHighlight = $null
                        
                        if ($control -is [System.Windows.Controls.CheckBox]) {
                            if ($control.Content.ToString().ToLower().Contains($searchText)) {
                                $matchFound = $true
                                $controlToHighlight = $control
                            }
                        }
                        elseif ($control -is [System.Windows.Controls.Border] -and $control.Name -like '*_LabelBorder') {
                            $labelText = if ($control.Child) { $control.Child.Text.ToLower() } else { "" }
                            $comboBox = if ($i + 1 -lt $controlsList.Count -and $controlsList[$i + 1] -is [System.Windows.Controls.ComboBox]) { $controlsList[$i + 1] } else { $null }
                            
                            # Check label text or combo box items
                            if ($labelText.Contains($searchText) -or ($comboBox -and (ComboBoxContainsMatch -comboBox $comboBox -searchText $searchText))) {
                                $matchFound = $true
                                $controlToHighlight = $control
                            }
                        }
                        
                        if ($matchFound -and $controlToHighlight) {
                            $controlToHighlight.Background = $highlightBrush
                            if ($null -eq $firstMatch) { $firstMatch = $controlToHighlight }
                        }
                    }
                }
            }
        }
        
        # Scroll to first match if not visible
        if ($firstMatch -and $tweaksScrollViewer) {
            ScrollToItemIfNotVisible -scrollViewer $tweaksScrollViewer -item $firstMatch -container $tweaksGrid
        }
    })

    # Add Ctrl+F keyboard shortcut to focus search box on current tab
    $window.Add_KeyDown({
        param($sender, $e)
        
        # Check if Ctrl+F was pressed
        if ($e.Key -eq [System.Windows.Input.Key]::F -and 
            ([System.Windows.Input.Keyboard]::Modifiers -band [System.Windows.Input.ModifierKeys]::Control)) {
            
            $currentTab = $tabControl.SelectedItem
            
            # Focus AppSearchBox if on App Removal tab
            if ($currentTab.Header -eq "App Removal" -and $appSearchBox) {
                $appSearchBox.Focus()
                $e.Handled = $true
            }
            # Focus TweakSearchBox if on Tweaks tab
            elseif ($currentTab.Header -eq "Tweaks" -and $tweakSearchBox) {
                $tweakSearchBox.Focus()
                $e.Handled = $true
            }
        }
    })

    # Wizard Navigation
    $tabControl = $window.FindName('MainTabControl')
    $previousBtn = $window.FindName('PreviousBtn')
    $nextBtn = $window.FindName('NextBtn')
    $userSelectionCombo = $window.FindName('UserSelectionCombo')
    $userSelectionDescription = $window.FindName('UserSelectionDescription')
    $otherUserPanel = $window.FindName('OtherUserPanel')
    $otherUsernameTextBox = $window.FindName('OtherUsernameTextBox')
    $usernameTextBoxPlaceholder = $window.FindName('UsernameTextBoxPlaceholder')
    $usernameValidationMessage = $window.FindName('UsernameValidationMessage')
    $appRemovalScopeCombo = $window.FindName('AppRemovalScopeCombo')
    $appRemovalScopeDescription = $window.FindName('AppRemovalScopeDescription')
    $appRemovalScopeSection = $window.FindName('AppRemovalScopeSection')
    $appRemovalScopeCurrentUser = $window.FindName('AppRemovalScopeCurrentUser')
    $appRemovalScopeTargetUser = $window.FindName('AppRemovalScopeTargetUser')

    # Navigation button handlers
    function UpdateNavigationButtons {
        $currentIndex = $tabControl.SelectedIndex
        $totalTabs = $tabControl.Items.Count
        
        $homeIndex = 0
        $overviewIndex = $totalTabs - 1

        # Navigation button visibility
        if ($currentIndex -eq $homeIndex) {
            $nextBtn.Visibility = 'Collapsed'
            $previousBtn.Visibility = 'Collapsed'
        } elseif ($currentIndex -eq $overviewIndex) {
            $nextBtn.Visibility = 'Collapsed'
            $previousBtn.Visibility = 'Visible'
        } else {
            $nextBtn.Visibility = 'Visible'
            $previousBtn.Visibility = 'Visible'
        }
        
        # Update progress indicators
        # Tab indices: 0=Home, 1=App Removal, 2=Tweaks, 3=Deployment Settings
        $blueColor = "#0067c0"
        $greyColor = "#808080"
        
        $progressIndicator1 = $window.FindName('ProgressIndicator1') # App Removal
        $progressIndicator2 = $window.FindName('ProgressIndicator2') # Tweaks
        $progressIndicator3 = $window.FindName('ProgressIndicator3') # Deployment Settings
        $bottomNavGrid = $window.FindName('BottomNavGrid')
        
        # Hide bottom navigation on home page
        if ($currentIndex -eq 0) {
            $bottomNavGrid.Visibility = 'Collapsed'
        } else {
            $bottomNavGrid.Visibility = 'Visible'
        }
        
        # Update indicator colors based on current tab
        # Indicator 1 (App Removal) - tab index 1
        if ($currentIndex -ge 1) {
            $progressIndicator1.Fill = $blueColor
        } else {
            $progressIndicator1.Fill = $greyColor
        }
        
        # Indicator 2 (Tweaks) - tab index 2
        if ($currentIndex -ge 2) {
            $progressIndicator2.Fill = $blueColor
        } else {
            $progressIndicator2.Fill = $greyColor
        }
        
        # Indicator 3 (Deployment Settings) - tab index 3
        if ($currentIndex -ge 3) {
            $progressIndicator3.Fill = $blueColor
        } else {
            $progressIndicator3.Fill = $greyColor
        }
    }

    # Update user selection description and show/hide other user panel
    $userSelectionCombo.Add_SelectionChanged({
        switch ($userSelectionCombo.SelectedIndex) {
            0 { 
                $userSelectionDescription.Text = "Changes will be applied to the currently logged-in user profile."
                $otherUserPanel.Visibility = 'Collapsed'
                $usernameValidationMessage.Text = ""
                # Show "Current user only" option, hide "Target user only" option
                $appRemovalScopeCurrentUser.Visibility = 'Visible'
                $appRemovalScopeTargetUser.Visibility = 'Collapsed'
                # Enable app removal scope selection for current user
                $appRemovalScopeCombo.IsEnabled = $true
                $appRemovalScopeCombo.SelectedIndex = 0
            }
            1 { 
                $userSelectionDescription.Text = "Changes will be applied to a different user profile on this system."
                $otherUserPanel.Visibility = 'Visible'
                $usernameValidationMessage.Text = ""
                # Hide "Current user only" option, show "Target user only" option
                $appRemovalScopeCurrentUser.Visibility = 'Collapsed'
                $appRemovalScopeTargetUser.Visibility = 'Visible'
                # Enable app removal scope selection for other user
                $appRemovalScopeCombo.IsEnabled = $true
                $appRemovalScopeCombo.SelectedIndex = 0
            }
            2 { 
                $userSelectionDescription.Text = "Changes will be applied to the default user template, affecting all new users created after this point. Useful for Sysprep deployment."
                $otherUserPanel.Visibility = 'Collapsed'
                $usernameValidationMessage.Text = ""
                # Hide other user options since they don't apply to default user template
                $appRemovalScopeCurrentUser.Visibility = 'Collapsed'
                $appRemovalScopeTargetUser.Visibility = 'Collapsed'
                # Lock app removal scope to "All users" when applying to sysprep
                $appRemovalScopeCombo.IsEnabled = $false
                $appRemovalScopeCombo.SelectedIndex = 0
            }
        }
    })

    # Helper function to update app removal scope description
    function UpdateAppRemovalScopeDescription {
        $selectedItem = $appRemovalScopeCombo.SelectedItem
        if ($selectedItem) {
            switch ($selectedItem.Content) {
                "All users" { 
                    $appRemovalScopeDescription.Text = "Apps will be removed for all users and from the Windows image to prevent reinstallation for new users."
                }
                "Current user only" { 
                    $appRemovalScopeDescription.Text = "Apps will only be removed for the current user. Other users and new users will not be affected."
                }
                "Target user only" { 
                    $appRemovalScopeDescription.Text = "Apps will only be removed for the specified target user. Other users and new users will not be affected."
                }
            }
        }
    }

    # Update app removal scope description
    $appRemovalScopeCombo.Add_SelectionChanged({
        UpdateAppRemovalScopeDescription
    })

    $otherUsernameTextBox.Add_TextChanged({
        # Show/hide placeholder
        if ([string]::IsNullOrWhiteSpace($otherUsernameTextBox.Text)) {
            $usernameTextBoxPlaceholder.Visibility = 'Visible'
        } else {
            $usernameTextBoxPlaceholder.Visibility = 'Collapsed'
        }
        
        ValidateOtherUsername
    })

    function ValidateOtherUsername {
        # Only validate if "Other User" is selected
        if ($userSelectionCombo.SelectedIndex -ne 1) {
            return $true
        }

        $username = $otherUsernameTextBox.Text.Trim()

        $errorBrush = [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#c42b1c"))
        $successBrush = [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#28a745"))

        if ($username.Length -eq 0) {
            $usernameValidationMessage.Text = "[X] Please enter a username"
            $usernameValidationMessage.Foreground = $errorBrush
            return $false
        }
        
        if ($username -eq $env:USERNAME) {
            $usernameValidationMessage.Text = "[X] Cannot enter your own username, use 'Current User' option instead"
            $usernameValidationMessage.Foreground = $errorBrush
            return $false
        }
        
        $userExists = CheckIfUserExists -Username $username

        if ($userExists) {
            $usernameValidationMessage.Text = "[OK] User found: $username"
            $usernameValidationMessage.Foreground = $successBrush
            return $true
        }

        $usernameValidationMessage.Text = "[X] User not found, please enter a valid username"
        $usernameValidationMessage.Foreground = $errorBrush
        return $false
    }

    function GenerateOverview {
        # Load Features.json
        $featuresJson = LoadJsonFile -filePath $script:FeaturesFilePath -expectedVersion "1.0"
        
        $changesList = @()
        
        # Collect selected apps
        $selectedAppsCount = 0
        foreach ($child in $appsPanel.Children) {
            if ($child -is [System.Windows.Controls.CheckBox] -and $child.IsChecked) {
                $selectedAppsCount++
            }
        }
        if ($selectedAppsCount -gt 0) {
            $changesList += "Remove $selectedAppsCount application(s)"
        }
        
        # Update app removal scope section based on whether apps are selected
        if ($selectedAppsCount -gt 0) {
            # Enable app removal scope selection (unless locked by sysprep mode)
            if ($userSelectionCombo.SelectedIndex -ne 2) {
                $appRemovalScopeCombo.IsEnabled = $true
            }
            $appRemovalScopeSection.Opacity = 1.0
            UpdateAppRemovalScopeDescription
        }
        else {
            # Disable app removal scope selection when no apps selected
            $appRemovalScopeCombo.IsEnabled = $false
            $appRemovalScopeSection.Opacity = 0.5
            $appRemovalScopeDescription.Text = "No apps selected for removal."
        }
        
        # Collect all ComboBox/CheckBox selections from dynamically created controls
        if ($script:UiControlMappings) {
            foreach ($mappingKey in $script:UiControlMappings.Keys) {
                $control = $window.FindName($mappingKey)
                $isSelected = $false
                
                # Check if it's a checkbox or combobox
                if ($control -is [System.Windows.Controls.CheckBox]) {
                    $isSelected = $control.IsChecked -eq $true
                }
                elseif ($control -is [System.Windows.Controls.ComboBox]) {
                    $isSelected = $control.SelectedIndex -gt 0
                }
                
                if ($control -and $isSelected) {
                    $mapping = $script:UiControlMappings[$mappingKey]
                    if ($mapping.Type -eq 'group') {
                        # For combobox: SelectedIndex 0 = No Change, so subtract 1 to index into Values
                        $selectedValue = $mapping.Values[$control.SelectedIndex - 1]
                        foreach ($fid in $selectedValue.FeatureIds) {
                            $feature = $featuresJson.Features | Where-Object { $_.FeatureId -eq $fid }
                            if ($feature) { $changesList += ($feature.Action + ' ' + $feature.Label) }
                        }
                    }
                    elseif ($mapping.Type -eq 'feature') {
                        $feature = $featuresJson.Features | Where-Object { $_.FeatureId -eq $mapping.FeatureId }
                        if ($feature) { $changesList += ($feature.Action + ' ' + $feature.Label) }
                    }
                }
            }
        }
        
        return $changesList
    }

    function ShowChangesOverview {
        $changesList = GenerateOverview

        if ($changesList.Count -eq 0) {
            Show-MessageBox -Message 'No changes have been selected.' -Title 'Selected Changes' -Button 'OK' -Icon 'Information'
            return
        }

        $message = ($changesList | ForEach-Object { "$([char]0x2022) $_" }) -join "`n"
        Show-MessageBox -Message $message -Title 'Selected Changes' -Button 'OK' -Icon 'None' -Width 600
    }

    $previousBtn.Add_Click({        
        if ($tabControl.SelectedIndex -gt 0) {
            $tabControl.SelectedIndex--
            UpdateNavigationButtons
        }
    })

    $nextBtn.Add_Click({        
        if ($tabControl.SelectedIndex -lt ($tabControl.Items.Count - 1)) {
            $tabControl.SelectedIndex++
            
            UpdateNavigationButtons
        }
    })

    # Handle Home Start button
    $homeStartBtn = $window.FindName('HomeStartBtn')
    $homeStartBtn.Add_Click({
        # Navigate to first tab after home (App Removal)
        $tabControl.SelectedIndex = 1
        UpdateNavigationButtons
    })

    # Handle Home Default Mode button - apply defaults and navigate directly to overview
    $homeDefaultModeBtn = $window.FindName('HomeDefaultModeBtn')
    $homeDefaultModeBtn.Add_Click({
        # Load and apply default settings
        $defaultsJson = LoadJsonFile -filePath $script:DefaultSettingsFilePath -expectedVersion "1.0"
        if ($defaultsJson) {
            ApplySettingsToUiControls -window $window -settingsJson $defaultsJson -uiControlMappings $script:UiControlMappings
        }

        # Select default apps
        foreach ($child in $appsPanel.Children) {
            if ($child -is [System.Windows.Controls.CheckBox]) {
                $child.IsChecked = ($child.SelectedByDefault -eq $true)
            }
        }

        # Navigate directly to the Deployment Settings tab
        $tabControl.SelectedIndex = 3
        UpdateNavigationButtons
    })

    # Handle Review Changes link button
    $reviewChangesBtn = $window.FindName('ReviewChangesBtn')
    $reviewChangesBtn.Add_Click({
        ShowChangesOverview
    })

    # Handle Apply Changes button - validates and immediately starts applying changes
    $deploymentApplyBtn = $window.FindName('DeploymentApplyBtn')
    $deploymentApplyBtn.Add_Click({
        if (-not (ValidateOtherUsername)) {
            Show-MessageBox -Message "Please enter a valid username." -Title "Invalid Username" -Button 'OK' -Icon 'Warning' | Out-Null
            return
        }

        # App Removal - collect selected apps from integrated UI
        $selectedApps = @()
        foreach ($child in $appsPanel.Children) {
            if ($child -is [System.Windows.Controls.CheckBox] -and $child.IsChecked) {
                $selectedApps += $child.Tag
            }
        }
        
        if ($selectedApps.Count -gt 0) {
            # Check if Microsoft Store is selected
            if ($selectedApps -contains "Microsoft.WindowsStore") {
                $result = Show-MessageBox -Message 'Are you sure you wish to uninstall the Microsoft Store? This app cannot easily be reinstalled.' -Title 'Are you sure?' -Button 'YesNo' -Icon 'Warning'

                if ($result -eq 'No') {
                    return
                }
            }
            
            AddParameter 'RemoveApps'
            AddParameter 'Apps' ($selectedApps -join ',')
            
            # Add app removal target parameter based on selection
            $selectedScopeItem = $appRemovalScopeCombo.SelectedItem
            if ($selectedScopeItem) {
                switch ($selectedScopeItem.Content) {
                    "All users" { 
                        AddParameter 'AppRemovalTarget' 'AllUsers'
                    }
                    "Current user only" { 
                        AddParameter 'AppRemovalTarget' 'CurrentUser'
                    }
                    "Target user only" { 
                        # Use the target username from Other User panel
                        AddParameter 'AppRemovalTarget' ($otherUsernameTextBox.Text.Trim())
                    }
                }
            }
        }

        # Apply dynamic tweaks selections
        if ($script:UiControlMappings) {
            foreach ($mappingKey in $script:UiControlMappings.Keys) {
                $control = $window.FindName($mappingKey)
                $isSelected = $false
                $selectedIndex = 0
                
                # Check if it's a checkbox or combobox
                if ($control -is [System.Windows.Controls.CheckBox]) {
                    $isSelected = $control.IsChecked -eq $true
                    $selectedIndex = if ($isSelected) { 1 } else { 0 }
                }
                elseif ($control -is [System.Windows.Controls.ComboBox]) {
                    $isSelected = $control.SelectedIndex -gt 0
                    $selectedIndex = $control.SelectedIndex
                }
                
                if ($control -and $isSelected) {
                    $mapping = $script:UiControlMappings[$mappingKey]
                    if ($mapping.Type -eq 'group') {
                        if ($selectedIndex -gt 0 -and $selectedIndex -le $mapping.Values.Count) {
                            $selectedValue = $mapping.Values[$selectedIndex - 1]
                            foreach ($fid in $selectedValue.FeatureIds) { 
                                AddParameter $fid
                            }
                        }
                    }
                    elseif ($mapping.Type -eq 'feature') {
                        AddParameter $mapping.FeatureId
                    }
                }
            }
        }

        $controlParamsCount = 0
        foreach ($Param in $script:ControlParams) {
            if ($script:Params.ContainsKey($Param)) {
                $controlParamsCount++
            }
        }

        # Check if any changes were selected
        $totalChanges = $script:Params.Count - $controlParamsCount

        # Apps parameter does not count as a change itself
        if ($script:Params.ContainsKey('Apps')) {
            $totalChanges = $totalChanges - 1
        }

        if ($totalChanges -eq 0) {
            Show-MessageBox -Message 'No changes have been selected, please select at least one option to proceed.' -Title 'No Changes Selected' -Button 'OK' -Icon 'Information'
            return
        }

        # Check RestorePointCheckBox
        $restorePointCheckBox = $window.FindName('RestorePointCheckBox')
        if ($restorePointCheckBox -and $restorePointCheckBox.IsChecked) {
            AddParameter 'CreateRestorePoint'
        }
        
        # Store selected user mode
        switch ($userSelectionCombo.SelectedIndex) {
            1 { AddParameter User ($otherUsernameTextBox.Text.Trim()) }
            2 { AddParameter Sysprep }
        }

        SaveSettings

        # Check if user wants to restart explorer
        $restartExplorerCheckBox = $window.FindName('RestartExplorerCheckBox')
        $shouldRestartExplorer = $restartExplorerCheckBox -and $restartExplorerCheckBox.IsChecked

        # Show the apply changes window
        Show-ApplyModal -Owner $window -RestartExplorer $shouldRestartExplorer

        # Close the main window after the apply dialog closes
        $window.Close()
    })

    # Initialize UI elements on window load
    $window.Add_Loaded({
        BuildDynamicTweaks

        LoadAppsIntoMainUI

        # Update Current User label with username
        if ($userSelectionCombo -and $userSelectionCombo.Items.Count -gt 0) {
            $currentUserItem = $userSelectionCombo.Items[0]
            if ($currentUserItem -is [System.Windows.Controls.ComboBoxItem]) {
                $currentUserItem.Content = "Current User ($(GetUserName))"
            }
        }

        # Disable Restart Explorer option if NoRestartExplorer parameter is set
        $restartExplorerCheckBox = $window.FindName('RestartExplorerCheckBox')
        if ($restartExplorerCheckBox -and $script:Params.ContainsKey("NoRestartExplorer")) {
            $restartExplorerCheckBox.IsChecked = $false
            $restartExplorerCheckBox.IsEnabled = $false
        }

        # Force Apply Changes To setting if Sysprep or User parameters are set
        if ($script:Params.ContainsKey("Sysprep")) {
            $userSelectionCombo.SelectedIndex = 2
            $userSelectionCombo.IsEnabled = $false
        }
        elseif ($script:Params.ContainsKey("User")) {
            $userSelectionCombo.SelectedIndex = 1
            $userSelectionCombo.IsEnabled = $false
            $otherUsernameTextBox.Text = $script:Params.Item("User")
            $otherUsernameTextBox.IsEnabled = $false
        }

        UpdateNavigationButtons
    })

    # Add event handler for tab changes
    $tabControl.Add_SelectionChanged({
        # Regenerate overview when switching to Overview tab
        if ($tabControl.SelectedIndex -eq ($tabControl.Items.Count - 2)) {
            GenerateOverview
        }
        UpdateNavigationButtons
    })

    # Handle Load Defaults button
    $loadDefaultsBtn = $window.FindName('LoadDefaultsBtn')
    $loadDefaultsBtn.Add_Click({
        $defaultsJson = LoadJsonFile -filePath $script:DefaultSettingsFilePath -expectedVersion "1.0"

        if (-not $defaultsJson) {
            Show-MessageBox -Message "Failed to load default settings file" -Title "Error" -Button 'OK' -Icon 'Error'
            return
        }
        
        ApplySettingsToUiControls -window $window -settingsJson $defaultsJson -uiControlMappings $script:UiControlMappings
    })

    # Handle Load Last Used settings and Load Last Used apps
    $loadLastUsedBtn = $window.FindName('LoadLastUsedBtn')
    $loadLastUsedAppsBtn = $window.FindName('LoadLastUsedAppsBtn')

    $lastUsedSettingsJson = LoadJsonFile -filePath $script:SavedSettingsFilePath -expectedVersion "1.0" -optionalFile

    $hasSettings = $false
    $appsSetting = $null
    if ($lastUsedSettingsJson -and $lastUsedSettingsJson.Settings) {
        foreach ($s in $lastUsedSettingsJson.Settings) {
            # Only count as hasSettings if a setting other than RemoveApps/Apps is present and true
            if ($s.Value -eq $true -and $s.Name -ne 'RemoveApps' -and $s.Name -ne 'Apps') { $hasSettings = $true }
            if ($s.Name -eq 'Apps' -and $s.Value) { $appsSetting = $s.Value }
        }
    }

    # Show option to load last used settings if they exist
    if ($hasSettings) {
        $loadLastUsedBtn.Add_Click({
            try {
                ApplySettingsToUiControls -window $window -settingsJson $lastUsedSettingsJson -uiControlMappings $script:UiControlMappings
            }
            catch {
                Show-MessageBox -Message "Failed to load last used settings: $_" -Title "Error" -Button 'OK' -Icon 'Error'
            }
        })
    }
    else {
        $loadLastUsedBtn.Visibility = 'Collapsed'
    }

    # Show option to load last used apps if they exist
    if ($appsSetting -and $appsSetting.ToString().Trim().Length -gt 0) {
        $loadLastUsedAppsBtn.Add_Click({
            try {
                $savedApps = @()
                if ($appsSetting -is [string]) { $savedApps = $appsSetting.Split(',') }
                elseif ($appsSetting -is [array]) { $savedApps = $appsSetting }
                $savedApps = $savedApps | ForEach-Object { $_.Trim() } | Where-Object { $_ -ne '' }

                foreach ($child in $appsPanel.Children) {
                    if ($child -is [System.Windows.Controls.CheckBox]) {
                        if ($savedApps -contains $child.Tag) { $child.IsChecked = $true } else { $child.IsChecked = $false }
                    }
                }
            }
            catch {
                Show-MessageBox -Message "Failed to load last used app selection: $_" -Title "Error" -Button 'OK' -Icon 'Error'
            }
        })
    }
    else {
        $loadLastUsedAppsBtn.Visibility = 'Collapsed'
    }

    # Clear All Tweaks button
    $clearAllTweaksBtn = $window.FindName('ClearAllTweaksBtn')
    $clearAllTweaksBtn.Add_Click({
        # Reset all ComboBoxes to index 0 (No Change) and uncheck all CheckBoxes
        if ($script:UiControlMappings) {
            foreach ($comboName in $script:UiControlMappings.Keys) {
                $control = $window.FindName($comboName)
                if ($control -is [System.Windows.Controls.CheckBox]) {
                    $control.IsChecked = $false
                }
                elseif ($control -is [System.Windows.Controls.ComboBox]) {
                    $control.SelectedIndex = 0
                }
            }
        } 
    })

    # Show the window
    return $window.ShowDialog()
}
