#Requires -Version 7.4

function Get-PVSPlatformData {
    <#
    .SYNOPSIS
        Detects Citrix Provisioning Services (PVS) platform information.

    .DESCRIPTION
        Uses a multi-tier detection architecture to identify PVS:
        - Tier 1: WMI Namespace (root/Citrix/PVS) - Primary, definitive
        - Tier 2: Personality.ini file - Secondary, definitive for active
        - Tier 3: Driver + Service detection - For active/capable status
        - Tier 4: Registry/Software detection - For capable status only

        Detection determines both active streaming status and PVS capability.

    .OUTPUTS
        [hashtable] with properties:
            IsPVSActive    - $true if currently booted from vDisk
            IsPVSCapable   - $true if PVS software installed (but not necessarily streaming)
            DiskMode       - 'Standard', 'Private', 'Difference', or $null
            vDiskName      - Name of the vDisk
            WriteCacheType - Write cache description string
            Version        - PVS version string

    .EXAMPLE
        $pvs = Get-PVSPlatformData
        if ($pvs.IsPVSActive) {
            Write-Host "Streaming from vDisk: $($pvs.vDiskName)"
        }

    .EXAMPLE
        $pvs = Get-PVSPlatformData
        if ($pvs.DiskMode -eq 'Private') {
            Write-Host "In maintenance mode - safe to make changes"
        }
    #>
    [CmdletBinding()]
    [OutputType([hashtable])]
    param()

    Write-vSEALLog -Message "Starting PVS platform detection..." -Level 'VERBOSE'

    # Initialize result structure
    $result = @{
        IsPVSActive    = $false
        IsPVSCapable   = $false
        DiskMode       = $null
        vDiskName      = $null
        WriteCacheType = $null
        Version        = $null
    }

    # DiskMode mapping
    $diskModeMap = @{
        'S' = 'Standard'
        'P' = 'Private'
        'D' = 'Difference'
    }

    # WriteCacheType mapping (integer to description)
    $writeCacheTypeMap = @{
        0  = 'Private Image (Writable)'
        3  = 'RAM'
        4  = 'Hard Disk'
        6  = 'RAM Disk'
        9  = 'RAM Cache with Overflow to Disk'
        12 = 'Device RAM with Overflow to HDD (Async IO)'
    }

    # ============================================================
    # TIER 1: WMI Namespace Detection (Primary - Definitive)
    # ============================================================
    Write-vSEALLog -Message "Tier 1: Checking WMI namespace root/Citrix/PVS..." -Level 'VERBOSE'

    $pvsTarget = $null
    $pvsVDisk = $null

    try {
        $pvsTarget = Get-CimInstance -ClassName 'PVS_Target' -Namespace 'root/Citrix/PVS' -ErrorAction Stop
        Write-vSEALLog -Message "PVS_Target class found in WMI namespace" -Level 'VERBOSE'
    }
    catch {
        Write-vSEALLog -Message "PVS_Target not available: $_" -Level 'VERBOSE'
    }

    if ($pvsTarget) {
        try {
            $pvsVDisk = Get-CimInstance -ClassName 'PVS_VDisk' -Namespace 'root/Citrix/PVS' -ErrorAction Stop
            Write-vSEALLog -Message "PVS_VDisk class found in WMI namespace" -Level 'VERBOSE'
        }
        catch {
            Write-vSEALLog -Message "PVS_VDisk not available: $_" -Level 'VERBOSE'
        }

        # WMI shows active streaming
        $result.IsPVSActive = $true
        $result.IsPVSCapable = $true
        $result.vDiskName = $pvsTarget.vDiskName

        # Map DiskMode
        $rawDiskMode = $pvsTarget.DiskMode
        if ($rawDiskMode -and $diskModeMap.ContainsKey($rawDiskMode)) {
            $result.DiskMode = $diskModeMap[$rawDiskMode]
        }
        elseif ($rawDiskMode) {
            $result.DiskMode = $rawDiskMode
        }

        # Map WriteCacheType
        $rawCacheType = $pvsTarget.CacheType
        if ($null -ne $rawCacheType) {
            if ($writeCacheTypeMap.ContainsKey([int]$rawCacheType)) {
                $result.WriteCacheType = $writeCacheTypeMap[[int]$rawCacheType]
            }
            else {
                $result.WriteCacheType = "Unknown ($rawCacheType)"
            }
        }

        # Get version from PVS_VDisk
        if ($pvsVDisk -and $pvsVDisk.VersionNumber) {
            $result.Version = $pvsVDisk.VersionNumber
        }

        Write-vSEALLog -Message "PVS detected via WMI: vDisk=$($result.vDiskName), Mode=$($result.DiskMode)" -Level 'VERBOSE'
        return $result
    }

    # ============================================================
    # TIER 2: Personality.ini Detection (Secondary - Definitive for Active)
    # ============================================================
    Write-vSEALLog -Message "Tier 2: Checking Personality.ini..." -Level 'VERBOSE'

    $personalityIniPath = 'C:\Personality.ini'
    if (Test-Path -Path $personalityIniPath) {
        Write-vSEALLog -Message "Personality.ini found at $personalityIniPath" -Level 'VERBOSE'

        try {
            $iniContent = Get-Content -Path $personalityIniPath -ErrorAction Stop

            # Ensure iniContent is an array of lines (handle both array and string input)
            if ($iniContent -is [string]) {
                $iniContent = $iniContent -split "`r?`n"
            }

            # Parse the INI file for PVS data
            $diskName = $null
            $writeCacheType = $null
            $diskMode = $null

            foreach ($line in $iniContent) {
                # [StringData] section
                if ($line -match '^\$DiskName=(.+)$') {
                    $diskName = $Matches[1].Trim()
                }
                if ($line -match '^\$WriteCacheType=(\d+)$') {
                    $writeCacheType = [int]$Matches[1]
                }
                # [CitrixData] section
                if ($line -match '^_DiskMode=(.+)$') {
                    $diskMode = $Matches[1].Trim()
                }
            }

            # If we found valid PVS data, mark as active
            if ($diskName -or $diskMode) {
                $result.IsPVSActive = $true
                $result.IsPVSCapable = $true
                $result.vDiskName = $diskName

                # Map DiskMode
                if ($diskMode -and $diskModeMap.ContainsKey($diskMode)) {
                    $result.DiskMode = $diskModeMap[$diskMode]
                }
                elseif ($diskMode) {
                    $result.DiskMode = $diskMode
                }

                # Map WriteCacheType
                if ($null -ne $writeCacheType) {
                    if ($writeCacheTypeMap.ContainsKey($writeCacheType)) {
                        $result.WriteCacheType = $writeCacheTypeMap[$writeCacheType]
                    }
                    else {
                        $result.WriteCacheType = "Unknown ($writeCacheType)"
                    }
                }

                Write-vSEALLog -Message "PVS detected via Personality.ini: vDisk=$diskName, Mode=$($result.DiskMode)" -Level 'VERBOSE'
                return $result
            }
        }
        catch {
            Write-vSEALLog -Message "Failed to read Personality.ini: $_" -Level 'VERBOSE'
        }
    }

    # ============================================================
    # TIER 3: Driver + Service Detection (For Capable/Active)
    # ============================================================
    Write-vSEALLog -Message "Tier 3: Checking CVhdMp driver and BNDevice service..." -Level 'VERBOSE'

    $driverRunning = $false
    $serviceRunning = $false

    # Check CVhdMp driver
    try {
        $cvhdmpDriver = Get-CimInstance -ClassName Win32_SystemDriver -Filter "Name='CVhdMp'" -ErrorAction Stop
        if ($cvhdmpDriver -and $cvhdmpDriver.State -eq 'Running') {
            $driverRunning = $true
            Write-vSEALLog -Message "CVhdMp driver is running" -Level 'VERBOSE'
        }
    }
    catch {
        Write-vSEALLog -Message "Failed to query CVhdMp driver: $_" -Level 'VERBOSE'
    }

    # Check BNDevice service
    try {
        $bnDeviceService = Test-vSEALServiceExists -Name 'BNDevice' -PassThru
        if ($bnDeviceService -and $bnDeviceService.Status -eq 'Running') {
            $serviceRunning = $true
            Write-vSEALLog -Message "BNDevice service is running" -Level 'VERBOSE'
        }
        elseif ($bnDeviceService) {
            Write-vSEALLog -Message "BNDevice service exists but is not running (Status: $($bnDeviceService.Status))" -Level 'VERBOSE'
            $result.IsPVSCapable = $true
        }
    }
    catch {
        Write-vSEALLog -Message "Failed to query BNDevice service: $_" -Level 'VERBOSE'
    }

    # Driver running + Service running = Active
    if ($driverRunning -and $serviceRunning) {
        $result.IsPVSActive = $true
        $result.IsPVSCapable = $true
        Write-vSEALLog -Message "PVS detected as active via driver + service" -Level 'VERBOSE'

        # Try to get version from CVhdMp.sys
        try {
            $driverPath = 'C:\Windows\System32\drivers\CVhdMp.sys'
            if (Test-Path -Path $driverPath) {
                $driverFile = Get-Item -Path $driverPath -ErrorAction Stop
                $result.Version = Get-vSEALFileVersion -File $driverFile
                Write-vSEALLog -Message "PVS version from driver: $($result.Version)" -Level 'VERBOSE'
            }
        }
        catch {
            Write-vSEALLog -Message "Failed to get driver version: $_" -Level 'VERBOSE'
        }

        return $result
    }

    # Driver running OR Service running = Capable
    if ($driverRunning -or $serviceRunning) {
        $result.IsPVSCapable = $true
        Write-vSEALLog -Message "PVS detected as capable (driver or service present)" -Level 'VERBOSE'
    }

    # ============================================================
    # TIER 4: Registry/Software Detection (For Capable only)
    # ============================================================
    Write-vSEALLog -Message "Tier 4: Checking registry for PVS software..." -Level 'VERBOSE'

    # Check Citrix Provisioning Services registry key
    $pvsRegPath = 'HKLM:\SOFTWARE\Citrix\ProvisioningServices'
    if (Test-Path -Path $pvsRegPath) {
        $result.IsPVSCapable = $true
        Write-vSEALLog -Message "PVS registry key found at $pvsRegPath" -Level 'VERBOSE'

        # Try to get version from registry
        try {
            $pvsReg = Get-ItemProperty -Path $pvsRegPath -ErrorAction SilentlyContinue
            if ($pvsReg -and $pvsReg.Version) {
                $result.Version = $pvsReg.Version
            }
        }
        catch {
            Write-vSEALLog -Message "Failed to read version from registry: $_" -Level 'VERBOSE'
        }

        return $result
    }

    # Check uninstall registry keys for "Citrix Provisioning"
    $uninstallPaths = @(
        'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*',
        'HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*'
    )

    foreach ($uninstallPath in $uninstallPaths) {
        try {
            $uninstallKeys = Get-ItemProperty -Path $uninstallPath -ErrorAction SilentlyContinue |
                Where-Object { $_.DisplayName -like '*Citrix Provisioning*' }

            if ($uninstallKeys) {
                $result.IsPVSCapable = $true
                Write-vSEALLog -Message "PVS detected via uninstall registry: $($uninstallKeys.DisplayName | Select-Object -First 1)" -Level 'VERBOSE'

                # Get version from uninstall key
                $firstKey = $uninstallKeys | Select-Object -First 1
                if ($firstKey.DisplayVersion) {
                    $result.Version = $firstKey.DisplayVersion
                }

                return $result
            }
        }
        catch {
            Write-vSEALLog -Message "Failed to query uninstall registry: $_" -Level 'VERBOSE'
        }
    }

    # No PVS detected
    Write-vSEALLog -Message "No PVS installation detected" -Level 'VERBOSE'
    return $result
}
