<#
.SYNOPSIS
    Applies registry settings to the Default User profile and the current logged-in user.

.DESCRIPTION
    Loads C:\Users\Default\NTUSER.DAT as a temporary hive (HKU\DefaultProfile), applies
    all settings, then unloads it. Every new user account created on this machine inherits
    these settings on first logon. The same settings are applied directly to the current
    user's HKCU. Does NOT block OneDrive re-launch - the Explorer namespace CLSID and RunOnce entries have been removed.

.ITEMS
    taskbar-zarovnat-vlevo-taskbaral-0: TaskbarAl = 0 in Explorer\Advanced. Windows 11 default is center-aligned (TaskbarAl = 1). Left alignment matches Windows 10 muscle memory and is strongly preferred by business users transitioning from Win10.
    taskbar-skryt-search-copilot-task-view-w: Hides Search box (SearchboxTaskbarMode=0), Copilot button (ShowCopilotButton=0), Task View (ShowTaskViewButton=0), Widgets (TaskbarDa=0), Chat/Teams (TaskbarMn=0). Reduces taskbar clutter to just pinned apps and running processes.
    taskbar-zobrazit-vsechny-ikonky-v-tray-s: Registers scheduled task that sets EnableAutoTray=0 on logon (repeat every 1 min). Windows 11 periodically re-hides tray icons - this task forces all icons visible so users can see VPN status, antivirus, backup, etc.
    taskbar-vyprazdnit-pinlist-taskbarlayout: Deploys TaskbarLayoutModification.xml. ProfileType=default: empty pins (clean slate). ProfileType=admin: Explorer+PowerShell+Edge. ProfileType=user: Explorer+Edge. Lock is removed by UnlockStartLayout task 5 min after first boot so users can customize.
    explorer-zobrazovat-pripony-souboru-hide: HideFileExt = 0 in Explorer\Advanced. Shows file extensions (.docx, .exe, .pdf, .ps1) in File Explorer. Essential for recognizing file types, avoiding phishing (fake .pdf.exe), and general IT work.
    explorer-otevrit-na-this-pc-launchto-1: LaunchTo = 1. File Explorer opens to "This PC" (drives view) instead of Quick Access. More useful on fresh machines where Quick Access history is empty and irrelevant.
    start-menu-vyprazdnit-piny-win11: ConfigureStartPins = {"pinnedList":[]} applied via registry. Removes all default Start menu tiles (Edge, Teams, Store, Office, Solitaire, etc.) from the Windows 11 Start grid. User starts with an empty, clean Start menu.
    start-menu-zakaz-bing-vyhledavani: DisableSearchBoxSuggestions = 1 in Software\Policies\Microsoft\Windows. Disables web search, Bing suggestions, and online results in Start menu search. Search returns only local apps, files, and settings.
    copilot-zakaz-turnoffwindowscopilot-1: TurnOffWindowsCopilot = 1 in SOFTWARE\Policies\Microsoft\Windows\WindowsCopilot. Disables the Windows Copilot sidebar entirely. Not suitable for most client environments (data privacy, AI usage policies).
    numlock-zapnout-pri-startu-initialkeyboa: InitialKeyboardIndicators = 2 in Default profile. Ensures NumLock is enabled when Windows starts. Standard expectation for users working with numeric data - prevents confusion on data entry.
    accent-barva-na-titulnich-listech-colorp: ColorPrevalence = 1 in Personalize key. Shows the X9.cz accent color (#223B47) on window title bars and borders. Gives all windows a consistent branded appearance.
    onedrive-runonce-klic-je-tady-smazat: REMOVED. The RunOnce key deletion and Explorer namespace CLSID removal were deleted - those registry tweaks prevented a freshly installed OneDrive (e.g. for M365) from launching. OneDrive AppX uninstall in step 01 is intentional; blocking re-launch is not.
    explorer-showrecent-0-showfrequent-0: ShowRecent=0 and ShowFrequent=0 in HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer. Hides Recent files and Frequent folders from Quick Access. Privacy improvement and cleaner File Explorer on fresh deployments.
    explorer-fullpath-1-cabinetstate: FullPath=1 in HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\CabinetState. Displays the full directory path (e.g. C:\Users\jan\Documents\Projekty) in the File Explorer title bar instead of just the folder name.
#>
param(
    [object]$Config,
    [string]$LogFile,
    [ValidateSet("default","admin","user")]
    [string]$ProfileType = "default"
)

$ErrorActionPreference = "Continue"

function Write-Log {
    param([string]$Message, [string]$Level = "INFO")
    $line = "[$(Get-Date -Format 'HH:mm:ss')] [$Level] $Message"
    $null = New-Item -ItemType Directory -Force -Path (Split-Path $LogFile -Parent) -ErrorAction SilentlyContinue
    Add-Content -Path $LogFile -Value $line -Encoding UTF8
}

function Get-Feature {
    param([object]$Cfg, [string]$StepID, [string]$FeatureID, [bool]$Default = $true)
    try {
        if ($null -eq $Cfg) { return $Default }
        $stepFeatures = $Cfg.features.$StepID
        if ($null -eq $stepFeatures) { return $Default }
        $val = $stepFeatures.$FeatureID
        if ($null -eq $val) { return $Default }
        return [bool]$val
    } catch { return $Default }
}

# -----------------------------------------------------------------------
# Helper - apply a registry setting to both Default hive and current HKCU
# -----------------------------------------------------------------------
function Grant-HiveWriteAccess {
    param([string]$HivePath)  # full path e.g. "Registry::HKU\DefaultProfile\Software\..."
    # Grants Administrators FullControl on a loaded hive key with restricted ACL.
    try {
        $acl  = Get-Acl -Path $HivePath -ErrorAction Stop
        $rule = New-Object System.Security.AccessControl.RegistryAccessRule(
            "BUILTIN\Administrators",
            [System.Security.AccessControl.RegistryRights]::FullControl,
            [System.Security.AccessControl.InheritanceFlags]"ContainerInherit,ObjectInherit",
            [System.Security.AccessControl.PropagationFlags]::None,
            [System.Security.AccessControl.AccessControlType]::Allow
        )
        $acl.SetAccessRule($rule)
        Set-Acl -Path $HivePath -AclObject $acl -ErrorAction Stop
    }
    catch {
        Write-Log "  Grant-HiveWriteAccess failed for $HivePath - $_" -Level WARN
    }
}

function Set-ProfileReg {
    param(
        [string]$SubKey,   # relative to HKCU (e.g. "Software\Microsoft\...")
        [string]$Name,
        $Value,
        [string]$Type = "DWord"
    )

    # Apply to loaded Default hive
    $defPath = "Registry::HKU\DefaultProfile\$SubKey"
    try {
        if (-not (Test-Path $defPath)) {
            New-Item -Path $defPath -Force -ErrorAction Stop | Out-Null
        }
        Set-ItemProperty -Path $defPath -Name $Name -Value $Value -Type $Type -Force -ErrorAction Stop
    }
    catch {
        # Retry after granting write access to parent key
        try {
            $parentPath = $defPath -replace '\\[^\\]+$', ''
            if (Test-Path $parentPath) { Grant-HiveWriteAccess -HivePath $parentPath }
            if (-not (Test-Path $defPath)) {
                New-Item -Path $defPath -Force -ErrorAction Stop | Out-Null
            }
            Set-ItemProperty -Path $defPath -Name $Name -Value $Value -Type $Type -Force -ErrorAction Stop
        }
        catch {
            Write-Log "  DEFAULT HIVE failed $SubKey\$Name - $_" -Level ERROR
        }
    }

    # Apply to current user as well
    $hkcuPath = "HKCU:\$SubKey"
    try {
        if (-not (Test-Path $hkcuPath)) {
            New-Item -Path $hkcuPath -Force -ErrorAction Stop | Out-Null
        }
        Set-ItemProperty -Path $hkcuPath -Name $Name -Value $Value -Type $Type -Force -ErrorAction Stop
        Write-Log "  SET $SubKey\$Name = $Value" -Level OK
    }
    catch {
        Write-Log "  HKCU failed $SubKey\$Name - $_" -Level ERROR
    }
}

function Remove-ProfileReg {
    param([string]$SubKey, [string]$Name)

    $defPath = "Registry::HKU\DefaultProfile\$SubKey"
    try {
        if (Test-Path $defPath) {
            Remove-ItemProperty -Path $defPath -Name $Name -Force -ErrorAction SilentlyContinue
        }
    }
    catch { }

    $hkcuPath = "HKCU:\$SubKey"
    try {
        if (Test-Path $hkcuPath) {
            Remove-ItemProperty -Path $hkcuPath -Name $Name -Force -ErrorAction SilentlyContinue
            Write-Log "  REMOVED $SubKey\$Name" -Level OK
        }
    }
    catch {
        Write-Log "  FAILED removing $SubKey\$Name - $_" -Level ERROR
    }
}

# -----------------------------------------------------------------------
# Load Default profile hive
# -----------------------------------------------------------------------
$hivePath = "C:\Users\Default\NTUSER.DAT"
$hiveKey  = "DefaultProfile"

Write-Log "Loading Default hive: $hivePath" -Level INFO

# Unload first in case previous run left it mounted
& reg unload "HKU\$hiveKey" 2>&1 | Out-Null

$loadResult = & reg load "HKU\$hiveKey" $hivePath 2>&1
if ($LASTEXITCODE -ne 0) {
    Write-Log "Failed to load Default hive: $loadResult" -Level ERROR
    exit 1
}
Write-Log "Default hive loaded" -Level OK

try {
    # -----------------------------------------------------------------------
    # Taskbar tweaks (alignment, buttons, tray, layout XML)
    # -----------------------------------------------------------------------
    if (Get-Feature $Config "defaultProfile" "taskbarTweaks") {
        Write-Log "Applying taskbar tweaks" -Level STEP

        $tbPath = "Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced"

        # Win11: align taskbar to left (0 = left, 1 = center)
        Set-ProfileReg -SubKey $tbPath -Name "TaskbarAl" -Value 0

        # Hide Search box / button - Win10/11 (0 = hidden, 1 = icon, 2 = full box)
        # Note: Win11 uses Search subkey, Win10 uses Explorer\Advanced - set both
        Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\Search" `
                       -Name "SearchboxTaskbarMode" -Value 0
        Set-ProfileReg -SubKey $tbPath -Name "SearchboxTaskbarMode" -Value 0

        # Hide Task View button
        Set-ProfileReg -SubKey $tbPath -Name "ShowTaskViewButton" -Value 0

        # Hide Widgets button
        Set-ProfileReg -SubKey $tbPath -Name "TaskbarDa" -Value 0

        # Hide Chat / Teams button
        Set-ProfileReg -SubKey $tbPath -Name "TaskbarMn" -Value 0

        # Hide Copilot button
        Set-ProfileReg -SubKey $tbPath -Name "ShowCopilotButton" -Value 0

        # Show all tray icons
        # EnableAutoTray = 0 works on Win10; Win11 ignores it but set anyway
        Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\Explorer" `
                       -Name "EnableAutoTray" -Value 0

        # Win11 workaround: clear cached tray icon streams so all icons appear on next login
        $trayNotifyKey = "HKCU:\Software\Classes\Local Settings\Software\Microsoft\Windows\CurrentVersion\TrayNotify"
        if (Test-Path $trayNotifyKey) {
            Remove-ItemProperty -Path $trayNotifyKey -Name "IconStreams"     -Force -ErrorAction SilentlyContinue
            Remove-ItemProperty -Path $trayNotifyKey -Name "PastIconsStream" -Force -ErrorAction SilentlyContinue
            Write-Log "  Cleared TrayNotify icon streams (Win11 systray workaround)" -Level OK
        }
        $defTrayKey = "Registry::HKU\DefaultProfile\Software\Classes\Local Settings\Software\Microsoft\Windows\CurrentVersion\TrayNotify"
        if (Test-Path $defTrayKey) {
            Remove-ItemProperty -Path $defTrayKey -Name "IconStreams"     -Force -ErrorAction SilentlyContinue
            Remove-ItemProperty -Path $defTrayKey -Name "PastIconsStream" -Force -ErrorAction SilentlyContinue
            Write-Log "  Cleared TrayNotify icon streams in Default hive" -Level OK
        }

        # Desktop icons - show This PC
        # CLSID {20D04FE0-3AEA-1069-A2D8-08002B30309D} = This PC / Computer
        Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\Explorer\HideDesktopIcons\NewStartPanel" `
                       -Name "{20D04FE0-3AEA-1069-A2D8-08002B30309D}" -Value 0

        # Taskbar pinned apps layout (Win10/11)
        # ProfileType: default = empty, admin = Explorer+PS+Edge, user = Explorer+Edge
        # Note: TaskbarLayoutModification.xml locks the taskbar temporarily.
        # UnlockStartLayout scheduled task removes the lock 5 min after first boot
        # so users can then customize pins freely.
        # Win11 24H2+ may require ProvisionedLayoutModification.xml format instead.
        Write-Log "  Writing taskbar layout (ProfileType=$ProfileType)" -Level INFO

        $taskbarLayoutDir = "C:\Users\Default\AppData\Local\Microsoft\Windows\Shell"
        if (-not (Test-Path $taskbarLayoutDir)) {
            New-Item -ItemType Directory -Path $taskbarLayoutDir -Force | Out-Null
        }

        $pinList = switch ($ProfileType) {
            "admin" {
@'
        <taskbar:DesktopApp DesktopApplicationLinkPath="%APPDATA%\Microsoft\Windows\Start Menu\Programs\System Tools\File Explorer.lnk"/>
        <taskbar:DesktopApp DesktopApplicationLinkPath="%APPDATA%\Microsoft\Windows\Start Menu\Programs\Windows PowerShell\Windows PowerShell.lnk"/>
        <taskbar:DesktopApp DesktopApplicationLinkPath="%PROGRAMDATA%\Microsoft\Windows\Start Menu\Programs\Microsoft Edge.lnk"/>
'@
            }
            "user" {
@'
        <taskbar:DesktopApp DesktopApplicationLinkPath="%APPDATA%\Microsoft\Windows\Start Menu\Programs\System Tools\File Explorer.lnk"/>
        <taskbar:DesktopApp DesktopApplicationLinkPath="%PROGRAMDATA%\Microsoft\Windows\Start Menu\Programs\Microsoft Edge.lnk"/>
'@
            }
            default { "" }   # empty = clean slate
        }

        $taskbarLayoutXml = @"
<?xml version="1.0" encoding="utf-8"?>
<LayoutModificationTemplate
    xmlns="http://schemas.microsoft.com/Start/2014/LayoutModification"
    xmlns:defaultlayout="http://schemas.microsoft.com/Start/2014/FullDefaultLayout"
    xmlns:start="http://schemas.microsoft.com/Start/2014/StartLayout"
    xmlns:taskbar="http://schemas.microsoft.com/Start/2014/TaskbarLayout"
    Version="1">
  <CustomTaskbarLayoutCollection PinListPlacement="Replace">
    <defaultlayout:TaskbarLayout>
      <taskbar:TaskbarPinList>
$pinList
      </taskbar:TaskbarPinList>
    </defaultlayout:TaskbarLayout>
  </CustomTaskbarLayoutCollection>
</LayoutModificationTemplate>
"@
        $taskbarLayoutXml | Set-Content -Path "$taskbarLayoutDir\LayoutModification.xml" -Encoding UTF8 -Force
        Write-Log "  Taskbar LayoutModification.xml written (profile: $ProfileType)" -Level OK

        # NumLock on startup
        Set-ProfileReg -SubKey "Control Panel\Keyboard" `
                       -Name "InitialKeyboardIndicators" -Value 2 -Type "String"

        # Accent color on title bars
        Set-ProfileReg -SubKey "Software\Microsoft\Windows\DWM" `
                       -Name "ColorPrevalence" -Value 1
    } else {
        Write-Log "taskbarTweaks feature disabled - skipping" -Level INFO
    }

    # -----------------------------------------------------------------------
    # Start menu tweaks (pins, Bing, Copilot, GameDVR)
    # -----------------------------------------------------------------------
    if (Get-Feature $Config "defaultProfile" "startMenuTweaks") {
        Write-Log "Applying Start menu tweaks" -Level STEP

        # Disable Bing search suggestions in Start menu
        Set-ProfileReg -SubKey "Software\Policies\Microsoft\Windows\Explorer" `
                       -Name "DisableSearchBoxSuggestions" -Value 1

        # Win11: empty Start menu pins
        Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\Start" `
                       -Name "ConfigureStartPins" `
                       -Value '{"pinnedList":[]}' `
                       -Type "String"

        # Hide "Recently added" apps in Start menu
        Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" `
                       -Name "Start_TrackProgs" -Value 0

        # Hide recently opened files/docs from Start menu
        Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" `
                       -Name "Start_TrackDocs" -Value 0

        # Disable Copilot
        Set-ProfileReg -SubKey "Software\Policies\Microsoft\Windows\WindowsCopilot" `
                       -Name "TurnOffWindowsCopilot" -Value 1

        # Disable GameDVR
        Set-ProfileReg -SubKey "System\GameConfigStore" `
                       -Name "GameDVR_Enabled" -Value 0
        Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\GameDVR" `
                       -Name "AppCaptureEnabled" -Value 0
    } else {
        Write-Log "startMenuTweaks feature disabled - skipping" -Level INFO
    }

    # -----------------------------------------------------------------------
    # Explorer tweaks (file extensions, LaunchTo, ShowRecent, FullPath)
    # -----------------------------------------------------------------------
    if (Get-Feature $Config "defaultProfile" "explorerTweaks") {
        Write-Log "Applying Explorer tweaks" -Level STEP

        $advPath = "Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced"

        # Show file extensions in Explorer
        Set-ProfileReg -SubKey $advPath -Name "HideFileExt" -Value 0

        # Open Explorer to This PC instead of Quick Access
        Set-ProfileReg -SubKey $advPath -Name "LaunchTo" -Value 1

        # Hide Recent files from Quick Access
        Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\Explorer" `
                       -Name "ShowRecent" -Value 0

        # Hide Frequent folders from Quick Access
        Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\Explorer" `
                       -Name "ShowFrequent" -Value 0

        # Show full path in Explorer title bar
        Set-ProfileReg -SubKey "Software\Microsoft\Windows\CurrentVersion\Explorer\CabinetState" `
                       -Name "FullPath" -Value 1
    } else {
        Write-Log "explorerTweaks feature disabled - skipping" -Level INFO
    }
}
finally {
    # -----------------------------------------------------------------------
    # Unload Default hive - always, even on error
    # -----------------------------------------------------------------------
    Write-Log "Unloading Default hive" -Level INFO
    [GC]::Collect()
    [GC]::WaitForPendingFinalizers()
    Start-Sleep -Milliseconds 500

    $unloadResult = & reg unload "HKU\$hiveKey" 2>&1
    if ($LASTEXITCODE -eq 0) {
        Write-Log "Default hive unloaded" -Level OK
    } else {
        Write-Log "Failed to unload Default hive: $unloadResult" -Level ERROR
    }
}

# -----------------------------------------------------------------------
# Restart Explorer to apply taskbar/tray changes to current session
# -----------------------------------------------------------------------
Write-Log "Restarting Explorer to apply taskbar changes" -Level INFO
try {
    Stop-Process -Name explorer -Force -ErrorAction SilentlyContinue
    Start-Sleep -Seconds 2
    Start-Process explorer
    Write-Log "Explorer restarted" -Level OK
}
catch {
    Write-Log "Explorer restart failed (non-fatal): $_" -Level WARN
}

Write-Log "Step 4 complete" -Level OK
