Views/CompliancePolicies.ps1

function Show-InTUICompliancePoliciesView {
    <#
    .SYNOPSIS
        Displays the Compliance Policies view with platform filtering and search.
    #>

    [CmdletBinding()]
    param()

    $exitView = $false

    while (-not $exitView) {
        Clear-Host
        Show-InTUIHeader
        Show-InTUIBreadcrumb -Path @('Home', 'Compliance Policies')

        $choices = @(
            'All Policies',
            'Windows Policies',
            'iOS/iPadOS Policies',
            'macOS Policies',
            'Android Policies',
            'Search Policies',
            '─────────────',
            'Back to Home'
        )

        $selection = Show-InTUIMenu -Title "[cyan]Compliance Policies[/]" -Choices $choices

        Write-InTUILog -Message "Compliance Policies view selection" -Context @{ Selection = $selection }

        switch ($selection) {
            'All Policies' {
                Show-InTUICompliancePolicyList
            }
            'Windows Policies' {
                Show-InTUICompliancePolicyList -PlatformFilter 'Windows'
            }
            'iOS/iPadOS Policies' {
                Show-InTUICompliancePolicyList -PlatformFilter 'iOS'
            }
            'macOS Policies' {
                Show-InTUICompliancePolicyList -PlatformFilter 'macOS'
            }
            'Android Policies' {
                Show-InTUICompliancePolicyList -PlatformFilter 'Android'
            }
            'Search Policies' {
                $searchTerm = Read-InTUITextInput -Message "[cyan]Search policies by name[/]"
                if ($searchTerm) {
                    Write-InTUILog -Message "Searching compliance policies" -Context @{ SearchTerm = $searchTerm }
                    Show-InTUICompliancePolicyList -SearchTerm $searchTerm
                }
            }
            'Back to Home' {
                $exitView = $true
            }
            default {
                continue
            }
        }
    }
}

function Show-InTUICompliancePolicyList {
    <#
    .SYNOPSIS
        Displays a list of device compliance policies with optional filtering.
    #>

    [CmdletBinding()]
    param(
        [Parameter()]
        [string]$PlatformFilter,

        [Parameter()]
        [string]$SearchTerm
    )

    $exitList = $false

    while (-not $exitList) {
        Clear-Host
        Show-InTUIHeader

        $breadcrumb = @('Home', 'Compliance Policies')
        if ($PlatformFilter) { $breadcrumb += "$PlatformFilter Policies" }
        elseif ($SearchTerm) { $breadcrumb += "Search: $SearchTerm" }
        else { $breadcrumb += 'All Policies' }
        Show-InTUIBreadcrumb -Path $breadcrumb

        $params = @{
            Uri      = '/deviceManagement/deviceCompliancePolicies'
            Beta     = $true
            PageSize = 25
            Select   = 'id,displayName,description,lastModifiedDateTime,createdDateTime,version'
        }

        if ($SearchTerm) {
            $safe = ConvertTo-InTUISafeFilterValue -Value $SearchTerm
            $params['Filter'] = "contains(displayName,'$safe')"
        }

        $policies = Show-InTUILoading -Title "[cyan]Loading compliance policies...[/]" -ScriptBlock {
            Get-InTUIPagedResults @params
        }

        if ($null -eq $policies -or $policies.Results.Count -eq 0) {
            Show-InTUIWarning "No compliance policies found."
            Read-InTUIKey
            $exitList = $true
            continue
        }

        # Client-side platform filtering (API doesn't support $filter on @odata.type)
        $filteredResults = $policies.Results
        if ($PlatformFilter) {
            $filteredResults = @($policies.Results | Where-Object {
                $typeInfo = Get-InTUICompliancePolicyType -ODataType $_.'@odata.type'
                $typeInfo.Platform -eq $PlatformFilter
            })

            if ($filteredResults.Count -eq 0) {
                Show-InTUIWarning "No $PlatformFilter compliance policies found."
                Read-InTUIKey
                $exitList = $true
                continue
            }
        }

        $policyChoices = @()
        foreach ($policy in $filteredResults) {
            $typeInfo = Get-InTUICompliancePolicyType -ODataType $policy.'@odata.type'
            $modified = Format-InTUIDate -DateString $policy.lastModifiedDateTime

            $displayName = "[white]$(ConvertTo-InTUISafeMarkup -Text $policy.displayName)[/] [grey]| $($typeInfo.FriendlyName) | $($typeInfo.Platform) | $modified[/]"
            $policyChoices += $displayName
        }

        $choiceMap = Get-InTUIChoiceMap -Choices $policyChoices
        $menuChoices = @($choiceMap.Choices + '─────────────' + 'Back')

        Show-InTUIStatusBar -Total $filteredResults.Count -Showing $filteredResults.Count -FilterText ($PlatformFilter ?? $SearchTerm)

        $selection = Show-InTUIMenu -Title "[cyan]Select a policy[/]" -Choices $menuChoices

        if ($selection -eq 'Back') {
            $exitList = $true
        }
        elseif ($selection -ne '─────────────') {
            $idx = $choiceMap.IndexMap[$selection]
            if ($null -ne $idx -and $idx -lt $filteredResults.Count) {
                Show-InTUICompliancePolicyDetail -PolicyId $filteredResults[$idx].id
            }
        }
    }
}

function Get-InTUICompliancePolicyType {
    <#
    .SYNOPSIS
        Maps a device compliance @odata.type to a friendly name and platform.
    #>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [string]$ODataType
    )

    switch -Wildcard ($ODataType) {
        '*windows10CompliancePolicy*'             { return @{ Platform = 'Windows'; FriendlyName = 'General' } }
        '*windowsPhone81CompliancePolicy*'        { return @{ Platform = 'Windows'; FriendlyName = 'Phone' } }
        '*iosCompliancePolicy*'                   { return @{ Platform = 'iOS'; FriendlyName = 'General' } }
        '*macOSCompliancePolicy*'                 { return @{ Platform = 'macOS'; FriendlyName = 'General' } }
        '*androidCompliancePolicy*'               { return @{ Platform = 'Android'; FriendlyName = 'General' } }
        '*androidWorkProfileCompliancePolicy*'    { return @{ Platform = 'Android'; FriendlyName = 'Work Profile' } }
        '*androidDeviceOwnerCompliancePolicy*'    { return @{ Platform = 'Android'; FriendlyName = 'Device Owner' } }
        default {
            $rawType = $ODataType -replace '#microsoft\.graph\.', ''
            return @{ Platform = 'Unknown'; FriendlyName = $rawType }
        }
    }
}

function Show-InTUICompliancePolicyDetail {
    <#
    .SYNOPSIS
        Displays detailed information about a specific compliance policy.
    #>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [string]$PolicyId
    )

    $exitDetail = $false

    while (-not $exitDetail) {
        Clear-Host
        Show-InTUIHeader

        $detailData = Show-InTUILoading -Title "[cyan]Loading policy details...[/]" -ScriptBlock {
            $pol = Invoke-InTUIGraphRequest -Uri "/deviceManagement/deviceCompliancePolicies/$PolicyId" -Beta
            $assign = Invoke-InTUIGraphRequest -Uri "/deviceManagement/deviceCompliancePolicies/$PolicyId/assignments" -Beta
            $devStatuses = Invoke-InTUIGraphRequest -Uri "/deviceManagement/deviceCompliancePolicies/$PolicyId/deviceStatuses?`$top=200" -Beta
            $settingSummaries = Invoke-InTUIGraphRequest -Uri "/deviceManagement/deviceCompliancePolicies/$PolicyId/deviceSettingStateSummaries" -Beta

            @{
                Policy           = $pol
                Assignments      = $assign
                DeviceStatuses   = $devStatuses
                SettingSummaries = $settingSummaries
            }
        }

        $policy = $detailData.Policy
        $assignments = $detailData.Assignments
        $deviceStatuses = $detailData.DeviceStatuses
        $settingSummaries = $detailData.SettingSummaries

        if ($null -eq $policy) {
            Show-InTUIError "Failed to load policy details."
            Read-InTUIKey
            return
        }

        Show-InTUIBreadcrumb -Path @('Home', 'Compliance Policies', $policy.displayName)

        Add-InTUIHistoryEntry -ViewType 'CompliancePolicy' -ViewId $PolicyId -DisplayName $policy.displayName

        $typeInfo = Get-InTUICompliancePolicyType -ODataType $policy.'@odata.type'

        # Panel 1: Policy Properties
        $propsContent = @"
[bold white]$(ConvertTo-InTUISafeMarkup -Text $policy.displayName)[/]

[grey]Type:[/] $($typeInfo.FriendlyName)
[grey]Platform:[/] $($typeInfo.Platform)
[grey]Description:[/] $(if ($policy.description) { $policy.description.Substring(0, [Math]::Min(200, $policy.description.Length)) } else { 'N/A' })
[grey]Created:[/] $(Format-InTUIDate -DateString $policy.createdDateTime)
[grey]Last Modified:[/] $(Format-InTUIDate -DateString $policy.lastModifiedDateTime)
[grey]Version:[/] $($policy.version ?? 'N/A')
"@


        Show-InTUIPanel -Title "[cyan]Policy Properties[/]" -Content $propsContent -BorderColor Cyan1

        # Panel 2: Assignments
        $assignmentCount = if ($assignments.value) { @($assignments.value).Count } else { 0 }
        $assignContent = "[grey]Total Assignments:[/] [white]$assignmentCount[/]"

        if ($assignments.value) {
            $assignContent += "`n"
            foreach ($assignment in $assignments.value) {
                $targetType = switch ($assignment.target.'@odata.type') {
                    '#microsoft.graph.allLicensedUsersAssignmentTarget' { '[blue]All Users[/]' }
                    '#microsoft.graph.allDevicesAssignmentTarget'       { '[blue]All Devices[/]' }
                    '#microsoft.graph.groupAssignmentTarget'            { "Group: $($assignment.target.groupId)" }
                    '#microsoft.graph.exclusionGroupAssignmentTarget'   { "[red]Exclude:[/] $($assignment.target.groupId)" }
                    default { $assignment.target.'@odata.type' -replace '#microsoft\.graph\.', '' }
                }
                $assignContent += "`n $targetType"
            }
        }

        Show-InTUIPanel -Title "[cyan]Assignments[/]" -Content $assignContent -BorderColor Cyan1

        # Panel 3: Device Status Summary
        $statusList = if ($deviceStatuses.value) { @($deviceStatuses.value) } else { @() }
        $compliant = @($statusList | Where-Object { $_.status -eq 'compliant' }).Count
        $nonCompliant = @($statusList | Where-Object { $_.status -eq 'nonCompliant' }).Count
        $errorCount = @($statusList | Where-Object { $_.status -eq 'error' }).Count
        $notApplicable = @($statusList | Where-Object { $_.status -eq 'notApplicable' }).Count

        $statusContent = @"
[grey]Total Devices:[/] [white]$($statusList.Count)[/]
[green]Compliant:[/] $compliant
[red]Non-Compliant:[/] $nonCompliant
[red]Error:[/] $errorCount
[grey]Not Applicable:[/] $notApplicable
"@


        Show-InTUIPanel -Title "[cyan]Device Status Summary[/]" -Content $statusContent -BorderColor Cyan1

        # Panel 4: Setting Status Summary
        $settingList = if ($settingSummaries.value) { @($settingSummaries.value) } else { @() }
        if ($settingList.Count -gt 0) {
            $settingRows = @()
            foreach ($setting in $settingList) {
                $settingRows += , @(
                    ($setting.settingName ?? $setting.instancePath ?? 'N/A'),
                    "[green]$($setting.compliantDeviceCount ?? 0)[/]",
                    "[red]$($setting.nonCompliantDeviceCount ?? 0)[/]",
                    "[red]$($setting.errorDeviceCount ?? 0)[/]",
                    "[grey]$($setting.notApplicableDeviceCount ?? 0)[/]"
                )
            }

            Show-InTUITable -Title "Setting Status Summary" -Columns @('Setting', 'Compliant', 'NonCompliant', 'Error', 'Not Applicable') -Rows $settingRows -BorderColor Cyan1
        }

        $actionChoices = @(
            'View Device Statuses',
            'View Per-Setting Status',
            '─────────────',
            'Back to Policies'
        )

        $action = Show-InTUIMenu -Title "[cyan]Policy Actions[/]" -Choices $actionChoices

        Write-InTUILog -Message "Compliance policy detail action" -Context @{ PolicyId = $PolicyId; PolicyName = $policy.displayName; Action = $action }

        switch ($action) {
            'View Device Statuses' {
                Show-InTUICompliancePolicyDeviceStatuses -PolicyId $PolicyId -PolicyName $policy.displayName
            }
            'View Per-Setting Status' {
                Show-InTUICompliancePolicySettingStatuses -PolicyId $PolicyId -PolicyName $policy.displayName
            }
            'Back to Policies' {
                $exitDetail = $true
            }
            default {
                continue
            }
        }
    }
}

function Show-InTUICompliancePolicyDeviceStatuses {
    <#
    .SYNOPSIS
        Displays device status table for a compliance policy.
    #>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [string]$PolicyId,

        [Parameter()]
        [string]$PolicyName
    )

    Clear-Host
    Show-InTUIHeader
    Show-InTUIBreadcrumb -Path @('Home', 'Compliance Policies', $PolicyName, 'Device Statuses')

    $statuses = Show-InTUILoading -Title "[cyan]Loading device statuses...[/]" -ScriptBlock {
        Invoke-InTUIGraphRequest -Uri "/deviceManagement/deviceCompliancePolicies/$PolicyId/deviceStatuses?`$top=50" -Beta
    }

    if (-not $statuses.value) {
        Show-InTUIWarning "No device status data available for this policy."
        Read-InTUIKey
        return
    }

    $rows = @()
    foreach ($status in $statuses.value) {
        $stateColor = switch ($status.status) {
            'compliant'     { 'green' }
            'nonCompliant'  { 'red' }
            'error'         { 'red' }
            'notApplicable' { 'grey' }
            default         { 'yellow' }
        }

        $rows += , @(
            ($status.deviceDisplayName ?? 'N/A'),
            "[$stateColor]$($status.status)[/]",
            ($status.userName ?? 'N/A'),
            (Format-InTUIDate -DateString $status.lastReportedDateTime)
        )
    }

    Show-InTUITable -Title "Device Statuses" -Columns @('Device', 'Status', 'User', 'Last Reported') -Rows $rows -BorderColor Cyan1
    Read-InTUIKey
}

function Show-InTUICompliancePolicySettingStatuses {
    <#
    .SYNOPSIS
        Displays per-setting status summary table for a compliance policy.
    #>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [string]$PolicyId,

        [Parameter()]
        [string]$PolicyName
    )

    Clear-Host
    Show-InTUIHeader
    Show-InTUIBreadcrumb -Path @('Home', 'Compliance Policies', $PolicyName, 'Per-Setting Status')

    $settingSummaries = Show-InTUILoading -Title "[cyan]Loading setting statuses...[/]" -ScriptBlock {
        Invoke-InTUIGraphRequest -Uri "/deviceManagement/deviceCompliancePolicies/$PolicyId/deviceSettingStateSummaries" -Beta
    }

    if (-not $settingSummaries.value) {
        Show-InTUIWarning "No setting status data available for this policy."
        Read-InTUIKey
        return
    }

    $rows = @()
    foreach ($setting in $settingSummaries.value) {
        $rows += , @(
            ($setting.settingName ?? $setting.instancePath ?? 'N/A'),
            "[green]$($setting.compliantDeviceCount ?? 0)[/]",
            "[red]$($setting.nonCompliantDeviceCount ?? 0)[/]",
            "[red]$($setting.errorDeviceCount ?? 0)[/]",
            "[orange1]$($setting.conflictDeviceCount ?? 0)[/]",
            "[grey]$($setting.notApplicableDeviceCount ?? 0)[/]"
        )
    }

    Show-InTUITable -Title "Per-Setting Status" -Columns @('Setting', 'Compliant', 'NonCompliant', 'Error', 'Conflict', 'Not Applicable') -Rows $rows -BorderColor Cyan1
    Read-InTUIKey
}