Modules/CyberConfigApp/CyberConfigAppHelpers/CyberConfigAppCommonUIHelper.psm1


# Add these Functions after the existing UI helper Function
Function Get-UIConfigCriticalValues {
    <#
    .SYNOPSIS
    Extracts unique criticality values from all baseline policies.
    .DESCRIPTION
    This Function scans all product baselines and returns unique criticality values for filter dropdown population.
    #>

    param()

    $criticalityValues = @()

    foreach ($productBaselines in $syncHash.Baselines.PSObject.Properties)
    {
        Write-DebugOutput -Message "Scanning product baselines for criticality values" -Source $MyInvocation.MyCommand -Level "Debug"
        foreach ($baseline in $productBaselines.Value)
        {
            if ($baseline.criticality -and $baseline.criticality -notin $criticalityValues) {
                Write-DebugOutput -Message "Found unique criticality value: $($baseline.criticality)" -Source $MyInvocation.MyCommand -Level "Debug"
                $criticalityValues += $baseline.criticality
            }
        }
    }

    Write-DebugOutput -Message "Found criticality values: $($criticalityValues -join ', ')" -Source $MyInvocation.MyCommand -Level "Info"
    return $criticalityValues | Sort-Object
}

Function Update-CriticalityDropdowns {
    <#
    .SYNOPSIS
    Updates criticality dropdown options based on currently loaded baseline data.
    .DESCRIPTION
    This function refreshes all criticality filter dropdowns to reflect the criticality values
    present in the currently loaded baseline policies.
    #>

    try {
        # Get current criticality values from loaded baselines
        $criticalityValues = Get-UIConfigCriticalValues

        if ($criticalityValues.Count -eq 0) {
            Write-DebugOutput -Message "No criticality values found in loaded baselines" -Source $MyInvocation.MyCommand -Level "Warning"
            return
        }

        Write-DebugOutput -Message "Updating criticality dropdowns with values: $($criticalityValues -join ', ')" -Source $MyInvocation.MyCommand -Level "Info"

        # Update criticality dropdowns for each tab type
        $tabTypes = $syncHash.UIConfigs.baselineControls.controlType

        foreach ($tabType in $tabTypes) {
            $criticalityComboBox = $syncHash."$($tabType)Criticality_ComboBox"

            if ($criticalityComboBox) {
                # Store current selection
                $currentSelection = $null
                if ($criticalityComboBox.SelectedItem) {
                    $currentSelection = $criticalityComboBox.SelectedItem.Tag
                }

                # Clear existing items
                $criticalityComboBox.Items.Clear()

                # Add "All Baselines" option
                $allItem = New-Object System.Windows.Controls.ComboBoxItem
                $allItem.Content = "All Baselines"
                $allItem.Tag = "ALL_BASELINES"
                [void]$criticalityComboBox.Items.Add($allItem)

                # Add specific criticality values
                foreach ($criticality in $criticalityValues) {
                    $item = New-Object System.Windows.Controls.ComboBoxItem
                    $item.Content = "$criticality only"
                    $item.Tag = $criticality
                    [void]$criticalityComboBox.Items.Add($item)
                }

                # Restore previous selection or default to "All"
                $criticalityComboBox.SelectedIndex = 0  # Default to "All Baselines"

                if ($currentSelection -and $currentSelection -ne "ALL_BASELINES") {
                    # Try to restore previous selection
                    for ($i = 0; $i -lt $criticalityComboBox.Items.Count; $i++) {
                        if ($criticalityComboBox.Items[$i].Tag -eq $currentSelection) {
                            $criticalityComboBox.SelectedIndex = $i
                            break
                        }
                    }
                }

                Write-DebugOutput -Message "Updated criticality dropdown for $tabType with $($criticalityValues.Count) values" -Source $MyInvocation.MyCommand -Level "Verbose"
            }
            else {
                Write-DebugOutput -Message "Criticality dropdown not found for tab type: $tabType" -Source $MyInvocation.MyCommand -Level "Warning"
            }
        }

        Write-DebugOutput -Message "Successfully updated all criticality dropdowns" -Source $MyInvocation.MyCommand -Level "Info"
    }
    catch {
        Write-DebugOutput -Message "Error updating criticality dropdowns: $($_.Exception.Message)" -Source $MyInvocation.MyCommand -Level "Error"
    }
}

# Helper Function to find controls in a container
Function Find-UIControlInContainer {
    <#
    .SYNOPSIS
    Finds all controls of a specific type within a container.
    .DESCRIPTION
    This function searches through the visual tree of a WPF container to find and return all controls of a specified type.
    .PARAMETER Container
    The container to search within, which can be a Window, UserControl, or any other WPF container.
    .PARAMETER ControlType
    The type of control to search for, specified as a string (e.g., "TextBox", "ComboBox", etc.).
    #>

    param(
        $Container,
        [string]$ControlType
    )

    $controls = @()

    if ($Container.GetType().Name -eq $ControlType) {
        $controls += $Container
    }

    if ($Container.Children) {
        foreach ($child in $Container.Children) {
            $controls += Find-UIControlInContainer -Container $child -ControlType $ControlType
        }
    }

    if ($Container.Content) {
        $controls += Find-UIControlInContainer -Container $Container.Content -ControlType $ControlType
    }

    return $controls
}

# Recursively find all controls
Function Find-UIControlElement {
    <#
    .SYNOPSIS
    Recursively searches for all control elements within a WPF container.
    .DESCRIPTION
    This Function traverses the visual tree to find and return all control elements contained within a specified parent container.
    #>

    param(
        [Parameter(Mandatory = $true)]
        [System.Windows.DependencyObject]$Parent
    )

    $results = @()

    for ($i = 0; $i -lt [System.Windows.Media.VisualTreeHelper]::GetChildrenCount($Parent); $i++) {
        $child = [System.Windows.Media.VisualTreeHelper]::GetChild($Parent, $i)
        if ($child -is [System.Windows.Controls.Control]) {
            $results += $child
        }
        $results += Find-UIControlElement -Parent $child
    }

    return $results
}

# Function to add event handlers to a specific control (for dynamically created controls)
Function Add-UIControlEventHandler {
    <#
    .SYNOPSIS
    Adds event handlers to dynamically created WPF controls.
    .DESCRIPTION
    This Function attaches appropriate event handlers to different types of WPF controls (TextBox, ComboBox, Button, etc.) for user interaction tracking.
    #>

    param(
        [System.Windows.Controls.Control]$Control
    )

    Write-DebugOutput -Message ("Adding event handlers for {0}: {1}" -f $Control.GetType().Name, $Control.Name) -Source $MyInvocation.MyCommand -Level "Debug"

    switch($Control.GetType().Name) {
        'TextBox' {
            # Add LostFocus event
            $Control.Add_LostFocus({
                $controlName = if ($this.Name) { $this.Name } else { "Unnamed TextBox" }
                $controlValue = $this.Text
                Write-DebugOutput -Message ("{0} [{1}] changed value to: {2}" -f $Control.GetType().Name, $controlName, $controlValue) -Source $MyInvocation.MyCommand -Level "Info"
            }.GetNewClosure())
            Write-DebugOutput -Message "Added LostFocus event handler to TextBox: $($Control.Name)" -Source $MyInvocation.MyCommand -Level "Debug"
        }
        'ComboBox' {
            # Add SelectionChanged event
            $Control.Add_SelectionChanged({
                $controlName = if ($this.Name) { $this.Name } else { "Unnamed ComboBox" }
                $selectedItem = $this.SelectedItem

                # Get the actual value instead of the ComboBoxItem object
                $actualValue = if ($selectedItem) {
                    if ($selectedItem.Tag) {
                        $selectedItem.Tag
                    } elseif ($selectedItem.Content) {
                        $selectedItem.Content
                    } else {
                        $selectedItem.ToString()
                    }
                } else {
                    "null"
                }

                Write-DebugOutput -Message ("{0} [{1}] changed value to: {2}" -f $this.GetType().Name, $controlName, $actualValue) -Source $MyInvocation.MyCommand -Level "Info"
            }.GetNewClosure())
            Write-DebugOutput -Message "Added SelectionChanged event handler to ComboBox: $($Control.Name)" -Source $MyInvocation.MyCommand -Level "Debug"
        }
        'Button' {
            # Add Click event
            $Control.Add_Click({
                $controlName = if ($this.Name) { $this.Name } else { "Unnamed Button" }
                Write-DebugOutput -Message ("{0} [{1}] was pressed" -f $Control.GetType().Name, $controlName) -Source $MyInvocation.MyCommand -Level "Info"
            }.GetNewClosure())
            Write-DebugOutput -Message "Added Click event handler to Button: $($Control.Name)" -Source $MyInvocation.MyCommand -Level "Debug"
        }
        'CheckBox' {
            # Add Checked event
            $Control.Add_Checked({
                $controlName = if ($this.Name) { $this.Name } else { "Unnamed CheckBox" }
                Write-DebugOutput -Message ("{0} [{1}] was checked" -f $Control.GetType().Name, $controlName) -Source $MyInvocation.MyCommand -Level "Info"
            }.GetNewClosure())

            # Add Unchecked event
            $Control.Add_Unchecked({
                $controlName = if ($this.Name) { $this.Name } else { "Unnamed CheckBox" }
                Write-DebugOutput -Message ("{0} [{1}] was unchecked" -f $Control.GetType().Name, $controlName) -Source $MyInvocation.MyCommand -Level "Info"
            }.GetNewClosure())
            Write-DebugOutput -Message "Added Checked/Unchecked event handlers to CheckBox: $($Control.Name)" -Source $MyInvocation.MyCommand -Level "Debug"
        }
    }
}

# Helper Function to find control by setting name
Function Find-UIFieldBySettingName {
    <#
    .SYNOPSIS
    Searches for WPF controls using various naming conventions.
    .DESCRIPTION
    This Function attempts to locate controls by trying multiple naming patterns and conventions commonly used in the application.
    #>

    param([string]$SettingName)

    Write-DebugOutput "Searching for control by setting name: $SettingName" -Source $MyInvocation.MyCommand -Level "Debug"

    # Define naming patterns to try
    $namingPatterns = @(
        $SettingName,                           # Direct name
        "$SettingName`_TextBox"                # SettingName_TextBox
        "$SettingName`_TextBlock"              # SettingName_TextBlock
        "$SettingName`_CheckBox"               # SettingName_CheckBox
        "$SettingName`_ComboBox"               # SettingName_ComboBox
        "$SettingName`_Label"                  # SettingName_Label
        "$SettingName`TextBox"                 # SettingNameTextBox
        "$SettingName`TextBlock"               # SettingNameTextBlock
        "$SettingName`CheckBox"                # SettingNameCheckBox
        "$SettingName`ComboBox"                # SettingNameComboBox
        "$SettingName`Label"                   # SettingNameLabel
    )

    Write-DebugOutput "Trying $($namingPatterns.Count) naming patterns for '$SettingName'" -Source $MyInvocation.MyCommand -Level "Verbose"

    # Try each pattern
    foreach ($pattern in $namingPatterns) {
        if ($syncHash.$pattern) {
            Write-DebugOutput "Found control '$pattern' for setting '$SettingName'" -Source $MyInvocation.MyCommand -Level "Debug"
            return $syncHash.$pattern
        }
    }

    Write-DebugOutput "No control found for setting '$SettingName' after trying all patterns" -Source $MyInvocation.MyCommand -Level "Error"
    return $null
}

# Function to search recursively for controls
Function Find-UIControlByName {
    <#
    .SYNOPSIS
    Recursively searches for a control by name within a parent container.
    .DESCRIPTION
    This nested Function traverses the visual tree to locate a control with a specific name.
    #>

    param($parent, $targetName)

    if ($parent.Name -eq $targetName) {
        return $parent
    }

    if ($parent.Children) {
        foreach ($child in $parent.Children) {
            $result = Find-UIControlByName -parent $child -targetName $targetName
            if ($result) { return $result }
        }
    }

    if ($parent.Content -and $parent.Content.Children) {
        foreach ($child in $parent.Content.Children) {
            $result = Find-UIControlByName -parent $child -targetName $targetName
            if ($result) { return $result }
        }
    }

    if ($parent.Items) {
        foreach ($item in $parent.Items) {
            if ($item.Content -and $item.Content.Children) {
                foreach ($child in $item.Content.Children) {
                    $result = Find-UIControlByName -parent $child -targetName $targetName
                    if ($result) { return $result }
                }
            }
        }
    }

    return $null
}

# Helper Function to update control value based on type
Function Set-UIControlValue {
    <#
    .SYNOPSIS
    Updates control values based on their type and handles focus preservation.
    .DESCRIPTION
    This Function sets values on different types of WPF controls while preserving cursor position and preventing timer interference.
    #>

    param(
        [object]$Control,
        [string[]]$Value,
        [string]$SettingKey
    )

    Write-DebugOutput -Message "Setting control value for $SettingKey on $($Control.GetType().Name)" -Source $MyInvocation.MyCommand -Level "Debug"

    switch ($Control.GetType().Name) {
        'TextBox' {
            # Clear placeholder styling if present
            if ($Control.Tag -eq "Placeholder") {
                $Control.Tag = "HasValue"
                $Control.Foreground = [System.Windows.Media.Brushes]::Black
                $Control.FontStyle = [System.Windows.FontStyles]::Normal
            }

            # Handle different value types appropriately
            if ($Value -is [array]) {
                $Control.Text = $Value -join ", "  # Join arrays with commas
            } else {
                $Control.Text = $Value    # Convert other types to string
            }
            $Control.UpdateLayout()
            Write-DebugOutput -Message "Successfully set TextBox value for $SettingKey to: $Value" -Source $MyInvocation.MyCommand -Level "Verbose"
        }
        'TextBlock' {
            <# Skip updating if user is currently typing in this control
            if ($Control.IsFocused -and $Control.IsKeyboardFocused) {
                return
            }
            #>

            $Control.Text = $Value
            $Control.UpdateLayout()

        }
        'CheckBox' {
            $Control.IsChecked = [bool]$Value
        }
        'ComboBox' {
            Set-UIComboBoxValue -ComboBox $Control -Value $Value -SettingKey $SettingKey
        }
        'Label' {
            $Control.Content = $Value
        }
        'String' {
            # Skip updating if user is currently typing in this control
            if ($Control.IsFocused -and $Control.IsKeyboardFocused) {
                return
            }
            $syncHash.$Control = $Value
        }
        default {
            Write-DebugOutput -Message ("Setting warning for {0}: {1}" -f $SettingKey,$Control.GetType().Name) -Source $MyInvocation.MyCommand -Level "Error"
        }
    }
}

# Function to search recursively for the list container
Function Find-UIListContainer {
    <#
    .SYNOPSIS
    Recursively searches for a list container control by name.
    .DESCRIPTION
    This nested Function traverses the WPF control hierarchy to locate a list container used for array field values.
    #>


    param($parent, $targetName)

    if ($parent.Name -eq $targetName) {
        return $parent
    }

    if ($parent.Children) {
        foreach ($child in $parent.Children) {
            $result = Find-UIListContainer -parent $child -targetName $targetName
            if ($result) { return $result }
        }
    }

    if ($parent.Content -and $parent.Content.Children) {
        foreach ($child in $parent.Content.Children) {
            $result = Find-UIListContainer -parent $child -targetName $targetName
            if ($result) { return $result }
        }
    }

    if ($parent.Items) {
        foreach ($item in $parent.Items) {
            if ($item.Content -and $item.Content.Children) {
                foreach ($child in $item.Content.Children) {
                    $result = Find-UIListContainer -parent $child -targetName $targetName
                    if ($result) { return $result }
                }
            }
        }
    }

    return $null
}

# Function to search recursively for the checkbox
Function Find-UICheckBox {
    <#
    .SYNOPSIS
    Recursively searches for a CheckBox control by name.
    .DESCRIPTION
    This nested Function traverses the WPF control hierarchy to locate a specific CheckBox control used for boolean field values.
    #>

    param($parent, $targetName)

    if ($parent.Name -eq $targetName -and $parent -is [System.Windows.Controls.CheckBox]) {
        return $parent
    }

    if ($parent.Children) {
        foreach ($child in $parent.Children) {
            $result = Find-UICheckBox -parent $child -targetName $targetName
            if ($result) { return $result }
        }
    }

    if ($parent.Content -and $parent.Content.Children) {
        foreach ($child in $parent.Content.Children) {
            $result = Find-UICheckBox -parent $child -targetName $targetName
            if ($result) { return $result }
        }
    }

    if ($parent.Items) {
        foreach ($item in $parent.Items) {
            if ($item.Content -and $item.Content.Children) {
                foreach ($child in $item.Content.Children) {
                    $result = Find-UICheckBox -parent $child -targetName $targetName
                    if ($result) { return $result }
                }
            }
        }
    }

    return $null
}

# Function to search recursively for the textbox
Function Find-UITextBox {
    <#
    .SYNOPSIS
    Recursively searches for a TextBox control by name.
    .DESCRIPTION
    This nested Function traverses the WPF control hierarchy to locate a specific TextBox control used for string field values.
    #>

    param($parent, $targetName)

    if ($parent.Name -eq $targetName -and $parent -is [System.Windows.Controls.TextBox]) {
        return $parent
    }

    if ($parent.Children) {
        foreach ($child in $parent.Children) {
            $result = Find-UITextBox -parent $child -targetName $targetName
            if ($result) { return $result }
        }
    }

    if ($parent.Content -and $parent.Content.Children) {
        foreach ($child in $parent.Content.Children) {
            $result = Find-UITextBox -parent $child -targetName $targetName
            if ($result) { return $result }
        }
    }

    if ($parent.Items) {
        foreach ($item in $parent.Items) {
            if ($item.Content -and $item.Content.Children) {
                foreach ($child in $item.Content.Children) {
                    $result = Find-UITextBox -parent $child -targetName $targetName
                    if ($result) { return $result }
                }
            }
        }
    }

    return $null
}

Function Find-UIDatePicker {
    <#
    .SYNOPSIS
    Recursively searches for a DatePicker control by name.
    .DESCRIPTION
    This nested Function traverses the WPF control hierarchy to locate a specific DatePicker control used for date field values.
    #>

    param($parent, $targetName)

    if ($parent.Name -eq $targetName -and $parent -is [System.Windows.Controls.DatePicker]) {
        return $parent
    }

    if ($parent.Children) {
        foreach ($child in $parent.Children) {
            $result = Find-UIDatePicker -parent $child -targetName $targetName
            if ($result) { return $result }
        }
    }

    if ($parent.Content -and $parent.Content.Children) {
        foreach ($child in $parent.Content.Children) {
            $result = Find-UIDatePicker -parent $child -targetName $targetName
            if ($result) { return $result }
        }
    }

    if ($parent.Items) {
        foreach ($item in $parent.Items) {
            if ($item.Content -and $item.Content.Children) {
                foreach ($child in $item.Content.Children) {
                    $result = Find-UIDatePicker -parent $child -targetName $targetName
                    if ($result) { return $result }
                }
            }
        }
    }

    return $null
}

# Helper Function to update ComboBox values
Function Set-UIComboBoxValue {
    <#
    .SYNOPSIS
    Updates ComboBox control selection to match a specified value.
    .DESCRIPTION
    This Function sets the selected item in a ComboBox control by matching the provided value against available items.
    #>

    param(
        [System.Windows.Controls.ComboBox]$ComboBox,
        [object]$Value,
        [string]$SettingKey
    )

    # Default ComboBox handling for other ComboBoxes
    # Try to find item by Tag first (common for environment selection)
    $selectedItem = $ComboBox.Items | Where-Object { $_.Tag -eq $Value }

    # If not found, try by Content
    if (-not $selectedItem) {
        $selectedItem = $ComboBox.Items | Where-Object { $_.Content -eq $Value }
    }

    # If still not found, try by string representation
    if (-not $selectedItem) {
        $selectedItem = $ComboBox.Items | Where-Object { $_.ToString() -eq $Value }
    }

    if ($selectedItem) {
        $syncHash.Window.Dispatcher.Invoke([Action]{
            $ComboBox.SelectedItem = $selectedItem
            $ComboBox.UpdateLayout()
            $ComboBox.InvalidateVisual()
            Write-DebugOutput -Message ("Setting ComboBox info for {0}: {1}" -f $SettingKey,$Value) -Source $MyInvocation.MyCommand -Level "Verbose"
        })
    } else {
        Write-DebugOutput -Message ("Could not find ComboBox [{0}] with value: {1}" -f $SettingKey,$Value) -Source $MyInvocation.MyCommand -Level "Error"
    }
}

# Function to validate UI field based on regex and required status
Function Confirm-UIRequiredField {
    <#
    .SYNOPSIS
    Confirms that a required field is filled out correctly.
    .DESCRIPTION
    This function checks if a UI element (e.g., TextBox, ComboBox) meets the specified requirements, such as being filled out and matching a regex pattern.
    .PARAMETER UIElement
    The UI element to validate, which can be a TextBox, ComboBox, etc.
    .PARAMETER RegexPattern
    The regex pattern to validate the field content against.
    .PARAMETER ErrorMessage
    The message to display if validation fails.
    .PARAMETER PlaceholderText
    Optional placeholder text to check against empty fields.
    .PARAMETER ShowMessageBox
    If specified, shows a message box with the error message if validation fails.
    .PARAMETER TestPath
    If specified, tests if the path exists for the current value.
    .PARAMETER RequiredFiles
    An array of required files to check for existence within the specified path.
    #>

    param(
        [System.Windows.Controls.Control]$UIElement,
        [string]$RegexPattern,
        [string]$ErrorMessage,
        [string]$PlaceholderText = "",
        [switch]$ShowMessageBox,
        [switch]$TestPath,
        [string[]]$RequiredFiles
    )

    $isValid = $true
    $currentValue = ""

    Write-DebugOutput -Message "Validating field: $($UIElement.Name) with regex: $RegexPattern" -Source $MyInvocation.MyCommand -Level "Debug"

    # Get the current value based on control type
    if ($UIElement -is [System.Windows.Controls.TextBox]) {
        $currentValue = $UIElement.Text
        Write-DebugOutput -Message "TextBox '$($UIElement.Name)' current value: $currentValue" -Source $MyInvocation.MyCommand -Level "Verbose"
    } elseif ($UIElement -is [System.Windows.Controls.ComboBox]) {
        $currentValue = $UIElement.SelectedItem
        Write-DebugOutput -Message "ComboBox '$($UIElement.Name)' current value: $currentValue" -Source $MyInvocation.MyCommand -Level "Verbose"
    }

    # Check if field is required and empty/placeholder
    if (([string]::IsNullOrWhiteSpace($currentValue) -or $currentValue -eq $PlaceholderText)) {
        $isValid = $false
    }
    # Check regex pattern if provided and field has content
    elseif (![string]::IsNullOrWhiteSpace($RegexPattern) -and
            ![string]::IsNullOrWhiteSpace($currentValue) -and
            $currentValue -ne $PlaceholderText -and
            -not ($currentValue -match $RegexPattern)) {
        $isValid = $false
    }
    # Check path existence if TestPath is specified
    elseif ($TestPath -and ![string]::IsNullOrWhiteSpace($currentValue) -and $currentValue -ne $PlaceholderText) {
        if (-not (Test-Path $currentValue)) {
            $isValid = $false
        }
        # Check for required files if specified
        elseif ($null -ne $RequiredFiles) {
            $foundRequiredFile = $false
            foreach ($requiredFile in $RequiredFiles) {
                $fullPath = Join-Path $currentValue $requiredFile
                if (Test-Path $fullPath) {
                    $foundRequiredFile = $true
                    break
                }
            }
            if (-not $foundRequiredFile) {
                $isValid = $false
            }
        }
    }

    # Apply visual feedback
    if ($UIElement -is [System.Windows.Controls.TextBox]) {
        if (-not $isValid) {
            Write-DebugOutput "Validation failed - applying red border to TextBox: $($UIElement.Name)" -Source "Confirm-UIRequiredField" -Level "Debug"
            $UIElement.BorderBrush = [System.Windows.Media.Brushes]::Red
            $UIElement.BorderThickness = "2"
        } else {
            Write-DebugOutput "Validation passed - applying gray border to TextBox: $($UIElement.Name)" -Source "Confirm-UIRequiredField" -Level "Debug"
            $UIElement.BorderBrush = [System.Windows.Media.Brushes]::Gray
            $UIElement.BorderThickness = "1"
        }
    }

    # Show error message if requested
    if (-not $isValid -and $ShowMessageBox -and ![string]::IsNullOrWhiteSpace($ErrorMessage)) {
        Write-DebugOutput "Displaying validation error message: $ErrorMessage" -Source "Confirm-UIRequiredField" -Level "Verbose"
        $syncHash.ShowMessageBox.Invoke($ErrorMessage, $syncHash.UIConfigs.localeTitles.ValidationError, [System.Windows.MessageBoxButton]::OK, [System.Windows.MessageBoxImage]::Warning)
    }

    Write-DebugOutput "Validation result for $($UIElement.Name): $isValid" -Source "Confirm-UIRequiredField" -Level "Debug"
    return $isValid
}

# Function to initialize placeholder text behavior for TextBox controls
Function Initialize-PlaceholderTextBox {
    <#
    .SYNOPSIS
    Configures placeholder text behavior for TextBox controls.
    .DESCRIPTION
    This Function sets up placeholder text that appears when TextBox controls are empty and manages the visual styling for placeholder display.
    #>

    param(
        [System.Windows.Controls.TextBox]$TextBox,
        [string]$PlaceholderText,
        [string]$InitialValue = $null
    )

    Write-DebugOutput "Initializing placeholder text for TextBox '$($TextBox.Name)' with placeholder '$PlaceholderText'" -Source "Initialize-PlaceholderTextBox" -Level "Debug"

    # Set initial state
    if (![string]::IsNullOrWhiteSpace($InitialValue)) {
        Write-DebugOutput "Setting initial value: '$InitialValue'" -Source "Initialize-PlaceholderTextBox" -Level "Verbose"
        $TextBox.Text = $InitialValue
        $TextBox.Foreground = [System.Windows.Media.Brushes]::Black
        $TextBox.FontStyle = [System.Windows.FontStyles]::Normal
        $TextBox.Tag = "HasValue"
    } else {
        Write-DebugOutput "Setting placeholder text display" -Source "Initialize-PlaceholderTextBox" -Level "Verbose"
        $TextBox.Text = $PlaceholderText
        $TextBox.Foreground = [System.Windows.Media.Brushes]::Gray
        $TextBox.FontStyle = [System.Windows.FontStyles]::Italic
        $TextBox.Tag = "Placeholder"
    }

    Write-DebugOutput "Adding GotFocus and LostFocus event handlers" -Source "Initialize-PlaceholderTextBox" -Level "Verbose"

    # Add GotFocus event handler
    $TextBox.Add_GotFocus({
        # Check by text content, not just Tag
        if ($this.Text -eq $PlaceholderText) {
            $this.Text = ""
            $this.Foreground = [System.Windows.Media.Brushes]::Black
            $this.FontStyle = [System.Windows.FontStyles]::Normal
            $this.Tag = "HasValue"
        }
    }.GetNewClosure())

    # Add LostFocus event handler
    $TextBox.Add_LostFocus({
        # Check if text is empty or whitespace
        if ([string]::IsNullOrWhiteSpace($this.Text)) {
            $this.Text = $PlaceholderText
            $this.Foreground = [System.Windows.Media.Brushes]::Gray
            $this.FontStyle = [System.Windows.FontStyles]::Italic
            $this.Tag = "Placeholder"
        } else {
            $this.Tag = "HasValue"
        }
    }.GetNewClosure())
}


# Create a new validation helper function
Function Invoke-RequiredFieldValidation {
    <#
    .SYNOPSIS
    Performs dynamic validation based on the requiredFields configuration
    .DESCRIPTION
    This function validates required fields based on JSON configuration, handling both always-required fields and conditionally-required fields based on toggle states
    #>


    $validationResults = @{
        IsValid = $true
        Errors = @()
        TabsToNavigate = @()
    }

    try {
        Write-DebugOutput -Message "Starting required field validation" -Source $MyInvocation.MyCommand -Level "Verbose"

        # Get required fields configuration
        $requiredFields = $syncHash.UIConfigs.requiredFields

        foreach ($fieldKey in $requiredFields.PSObject.Properties.Name) {
            $fieldConfig = $requiredFields.$fieldKey
            $shouldValidate = $false

            Write-DebugOutput -Message "Processing required field: $fieldKey" -Source $MyInvocation.MyCommand -Level "Verbose"

            # Determine if this field should be validated based on trigger
            switch ($fieldConfig.toggleTrigger) {
                "OnClick" {
                    # Always validate these fields
                    $shouldValidate = $true
                    Write-DebugOutput -Message "Field $fieldKey is always required (OnClick)" -Source $MyInvocation.MyCommand -Level "Verbose"
                }
                default {
                    # Check if the toggle is checked for conditional validation
                    $toggleControl = $syncHash.($fieldConfig.toggleTrigger)
                    if ($toggleControl -and $toggleControl -is [System.Windows.Controls.CheckBox]) {
                        $shouldValidate = $toggleControl.IsChecked
                        Write-DebugOutput -Message "Field $fieldKey conditional validation - Toggle $($fieldConfig.toggleTrigger) is checked: $shouldValidate" -Source $MyInvocation.MyCommand -Level "Verbose"
                    } else {
                        Write-DebugOutput -Message "Toggle control $($fieldConfig.toggleTrigger) not found for field $fieldKey" -Source $MyInvocation.MyCommand -Level "Warning"
                    }
                }
            }

            if ($shouldValidate) {
                # Get the UI element
                $uiElement = $syncHash.($fieldConfig.fieldName)

                if (-not $uiElement) {
                    Write-DebugOutput -Message "UI element $($fieldConfig.fieldName) not found for field $fieldKey" -Source $MyInvocation.MyCommand -Level "Warning"
                    continue
                }

                # Get validation pattern
                $validationPattern = $null
                $placeholderText = ""

                if ($fieldConfig.validationPatternName -and $syncHash.UIConfigs.valueValidations.($fieldConfig.validationPatternName)) {
                    $validationPattern = $syncHash.UIConfigs.valueValidations.($fieldConfig.validationPatternName).pattern
                }

                if ($syncHash.UIConfigs.localePlaceholder.($fieldConfig.fieldName)) {
                    $placeholderText = $syncHash.UIConfigs.localePlaceholder.($fieldConfig.fieldName)
                }

                # Perform validation based on field type
                $isFieldValid = $false

                if ($fieldKey -eq "OPAPath") {
                    # Special validation for OPA path
                    $isFieldValid = Confirm-UIRequiredField -UIElement $uiElement `
                                                      -PlaceholderText $placeholderText `
                                                      -TestPath `
                                                      -RequiredFiles @("opa_windows_amd64.exe", "opa.exe")
                } else {
                    # Standard validation
                    $isFieldValid = Confirm-UIRequiredField -UIElement $uiElement `
                                                      -RegexPattern $validationPattern `
                                                      -PlaceholderText $placeholderText
                }

                if (-not $isFieldValid) {
                    $validationResults.IsValid = $false

                    # Get error message
                    $errorKey = $fieldKey + "Validation"
                    if ($syncHash.UIConfigs.localeErrorMessages.$errorKey) {
                        $errorMessage = $syncHash.UIConfigs.localeErrorMessages.$errorKey
                    } else {
                        $errorMessage = "Field '$fieldKey' is required and must be valid."
                    }

                    $validationResults.Errors += $errorMessage

                    # Find which tab this field belongs to
                    $tabToNavigate = Find-TabForField -FieldKey $fieldKey
                    if ($tabToNavigate -and $tabToNavigate -notin $validationResults.TabsToNavigate) {
                        $validationResults.TabsToNavigate += $tabToNavigate
                    }

                    Write-DebugOutput -Message "Validation failed for field $fieldKey in tab $tabToNavigate" -Source $MyInvocation.MyCommand -Level "Info"
                }
            }
        }

        # Special validation for ProductNames (not in requiredFields but still required)
        $minimumRequired = if ($syncHash.UIConfigs.MinimumProductsRequired) { $syncHash.UIConfigs.MinimumProductsRequired } else { 1 }
        if (-not $syncHash.GeneralSettingsData.ProductNames -or $syncHash.GeneralSettingsData.ProductNames.Count -lt $minimumRequired) {
            $validationResults.IsValid = $false
            $validationResults.Errors += ($syncHash.UIConfigs.localeErrorMessages.ProductSelection -f $minimumRequired)

            $tabToNavigate = Find-TabForField -FieldKey "ProductNames"
            if ($tabToNavigate -and $tabToNavigate -notin $validationResults.TabsToNavigate) {
                $validationResults.TabsToNavigate += $tabToNavigate
            }
        }

        Write-DebugOutput -Message "Validation completed. Valid: $($validationResults.IsValid), Errors: $($validationResults.Errors.Count)" -Source $MyInvocation.MyCommand -Level "Info"

    } catch {
        Write-DebugOutput -Message "Error in validation: $($_.Exception.Message)" -Source $MyInvocation.MyCommand -Level "Error"
        $validationResults.IsValid = $false
        $validationResults.Errors += "Validation system error: $($_.Exception.Message)"
    }

    return $validationResults
}

Function Find-TabForField {
    <#
    .SYNOPSIS
    Finds which tab a field belongs to based on settingsControl configuration
    .DESCRIPTION
    Uses the settingsControl mapping to determine which tab contains a specific field
    #>

    param(
        [Parameter(Mandatory = $true)]
        [string]$FieldKey
    )

    try {
        $settingsControls = $syncHash.UIConfigs.settingsControl

        foreach ($tabName in $settingsControls.PSObject.Properties.Name) {
            $tabConfig = $settingsControls.$tabName

            if ($tabConfig.validationKeys -and $tabConfig.validationKeys -contains $FieldKey) {
                # Map tab names to actual tab controls
                switch ($tabName) {
                    "MainTab" { return $syncHash.MainTab }
                    "AdvancedTab" { return $syncHash.AdvancedTab }
                    "GlobalTab" { return $syncHash.GlobalTab }
                    default {
                        # Try to find tab by name
                        $tabControl = $syncHash.$tabName
                        if ($tabControl) {
                            return $tabControl
                        }
                    }
                }
            }
        }

        # Fallback - if not found, return MainTab
        Write-DebugOutput -Message "Tab not found for field $FieldKey, defaulting to MainTab" -Source $MyInvocation.MyCommand -Level "Warning"
        return $syncHash.MainTab

    } catch {
        Write-DebugOutput -Message "Error finding tab for field $FieldKey`: $($_.Exception.Message)" -Source $MyInvocation.MyCommand -Level "Error"
        return $syncHash.MainTab
    }
}

Function Switch-FirstErrorTab {
    <#
    .SYNOPSIS
    Navigates to the first tab that contains validation errors
    #>

    param(
        [Parameter(Mandatory = $true)]
        [array]$TabsToNavigate
    )

    if ($TabsToNavigate.Count -gt 0) {
        # Navigate to the first tab with errors
        $firstTab = $TabsToNavigate[0]
        $syncHash.MainTabControl.SelectedItem = $firstTab

        Write-DebugOutput -Message "Navigated to tab with validation errors" -Source $MyInvocation.MyCommand -Level "Info"
    }
}