categories/Preferences.ps1

# Preferences category: taskbar/explorer/personalization preferences. All HKCU, no elevation.
# research.md -> preferences category table. Does NOT duplicate widgets (feature 001) or
# file-extension visibility (explorer-start, feature 001) - FR-039.

function Get-OctaPreferencesCategory {
    [CmdletBinding()]
    param()
    return [pscustomobject]@{
        Id                          = 'preferences'
        DisplayName                 = 'Preferences'
        Description                 = 'Taskbar, dark mode, hidden files, clipboard history, and more'
        RequiresElevation           = $false
        ContainsIrreversibleActions = $false
        GetActionsFunction          = 'Get-OctaPreferencesActions'
        ApplyActionFunction         = 'Set-OctaPreferencesAction'
    }
}

function Get-OctaPreferencesActions {
    [CmdletBinding()]
    param()
    $actions = @()
    $advancedKey = 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced'
    $personalizeKey = 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize'

    $simpleDwordTargets = @(
        @{ Key = $advancedKey; Name = 'TaskbarAl'; Target = 1 } # 1 = center (Windows 11 default), was 0 = left
        @{ Key = $advancedKey; Name = 'ShowSecondsInSystemClock'; Target = 0 } # 0 = hide seconds (Windows default), was 1 = show
        @{ Key = $personalizeKey; Name = 'AppsUseLightTheme'; Target = 0 }
        @{ Key = $personalizeKey; Name = 'SystemUsesLightTheme'; Target = 0 }
        @{ Key = $advancedKey; Name = 'Hidden'; Target = 1 }
        @{ Key = 'HKCU:\Software\Microsoft\Clipboard'; Name = 'EnableClipboardHistory'; Target = 1 }
        @{ Key = $advancedKey; Name = 'UseCompactMode'; Target = 1 }
        @{ Key = $advancedKey; Name = 'SnapAssist'; Target = 1 }
        @{ Key = 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Search'; Name = 'BingSearchEnabled'; Target = 0 }
        # 006: taskbar/Start menu granularity. Each of these is a tri-state or multi-value
        # Windows setting (Windows11Debloat exposes several flags per item, one per possible
        # value) - Octa's Action model is single-direction, so one representative, decluttering
        # -leaning value is picked per item rather than exposing every possible variant.
        @{ Key = $advancedKey; Name = 'TaskbarGlomLevel'; Target = 2 } # never combine buttons
        @{ Key = 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Search'; Name = 'SearchboxTaskbarMode'; Target = 0 } # hide search box
        @{ Key = $advancedKey; Name = 'ShowTaskViewButton'; Target = 0 }
        @{ Key = $advancedKey; Name = 'MultiTaskingAltTabFilter'; Target = 0 } # 3 most recent tabs
        @{ Key = $advancedKey; Name = 'LastActiveClick'; Target = 1 }
        @{ Key = $advancedKey; Name = 'EnableSnapBar'; Target = 0 } # Snap Layouts flyout - distinct from SnapAssist above
    )

    foreach ($t in $simpleDwordTargets) {
        $current = (Get-ItemProperty -Path $t.Key -Name $t.Name -ErrorAction SilentlyContinue).($t.Name)
        if ($null -eq $current -or $current -ne $t.Target) {
            $displayCurrent = if ($null -eq $current) { '(not set)' } else { $current }
            $actions += New-OctaAction -TargetType Registry -TargetIdentifier "$($t.Key)|$($t.Name)" `
                -CurrentValue $displayCurrent -PlannedValue $t.Target -Reversible $true -RiskLevel Safe
        }
    }

    # Taskbar End Task - key may not exist yet.
    $devSettingsKey = "$advancedKey\TaskbarDeveloperSettings"
    $currentEndTask = (Get-ItemProperty -Path $devSettingsKey -Name 'TaskbarEndTask' -ErrorAction SilentlyContinue).TaskbarEndTask
    if ($null -eq $currentEndTask -or $currentEndTask -ne 1) {
        $displayCurrent = if ($null -eq $currentEndTask) { '(not set)' } else { $currentEndTask }
        $actions += New-OctaAction -TargetType Registry -TargetIdentifier "$devSettingsKey|TaskbarEndTask" `
            -CurrentValue $displayCurrent -PlannedValue 1 -Reversible $true -RiskLevel Safe
    }

    # Classic context menu - default value of a CLSID InprocServer32 key.
    $classicMenuKey = 'HKCU:\Software\Classes\CLSID\{86ca1aa0-34aa-4e8b-a509-50c905bae2a2}\InprocServer32'
    $currentDefault = (Get-ItemProperty -Path $classicMenuKey -Name '(default)' -ErrorAction SilentlyContinue).'(default)'
    if ($currentDefault -ne '') {
        $displayCurrent = if ($null -eq $currentDefault) { '(not set)' } else { $currentDefault }
        $actions += New-OctaAction -TargetType Registry -TargetIdentifier "$classicMenuKey|(default)" `
            -CurrentValue $displayCurrent -PlannedValue '' -Reversible $true -RiskLevel Safe
    }

    # NumLock on login - String value, HKCU-scoped (see spec.md Assumptions for scope limit).
    $kbKey = 'HKCU:\Control Panel\Keyboard'
    $currentNumLock = (Get-ItemProperty -Path $kbKey -Name 'InitialKeyboardIndicators' -ErrorAction SilentlyContinue).InitialKeyboardIndicators
    if ($currentNumLock -ne '2') {
        $displayCurrent = if ($null -eq $currentNumLock) { '(not set)' } else { $currentNumLock }
        $actions += New-OctaAction -TargetType Registry -TargetIdentifier "$kbKey|InitialKeyboardIndicators" `
            -CurrentValue $displayCurrent -PlannedValue '2' -Reversible $true -RiskLevel Safe
    }

    return $actions
}

function Set-OctaPreferencesAction {
    [CmdletBinding()]
    param([Parameter(Mandatory)]$Action)
    $keyPath, $valueName = $Action.TargetIdentifier -split '\|', 2
    if (-not (Test-Path $keyPath)) {
        New-Item -Path $keyPath -Force | Out-Null
    }
    if ($valueName -eq '(default)') {
        Set-Item -Path $keyPath -Value $Action.PlannedValue
    }
    elseif ($valueName -eq 'InitialKeyboardIndicators') {
        Set-ItemProperty -Path $keyPath -Name $valueName -Value $Action.PlannedValue -Type String
    }
    else {
        Set-ItemProperty -Path $keyPath -Name $valueName -Value $Action.PlannedValue -Type DWord
    }
}