Private/GlobalSearch.ps1

# InTUI Global Search
# Cross-entity incremental search

function Invoke-InTUIGlobalSearch {
    <#
    .SYNOPSIS
        Performs a global search across devices, apps, users, and groups.
    #>

    [CmdletBinding()]
    param()

    $exitSearch = $false

    while (-not $exitSearch) {
        Clear-Host
        Show-InTUIHeader
        Show-InTUIBreadcrumb -Path @('Home', 'Global Search')

        Write-InTUIText "[bold]Global Search[/]"
        Write-InTUIText "[grey]Search across devices, apps, users, and groups[/]"
        Write-InTUIText ""

        $searchTerm = Read-InTUITextInput -Message "[blue]Enter search term (min 3 characters)[/]"

        if (-not $searchTerm -or $searchTerm.Length -lt 3) {
            if (-not $searchTerm) {
                $exitSearch = $true
                continue
            }
            Show-InTUIWarning "Search term must be at least 3 characters."
            Read-InTUIKey
            continue
        }

        Write-InTUILog -Message "Global search initiated" -Context @{ SearchTerm = $searchTerm }

        $results = Show-InTUILoading -Title "[blue]Searching...[/]" -ScriptBlock {
            $safe = ConvertTo-InTUISafeFilterValue -Value $searchTerm
            $allResults = @{
                Devices = @()
                Apps = @()
                Users = @()
                Groups = @()
            }

            # Search devices
            $deviceResponse = Invoke-InTUIGraphRequest -Uri "/deviceManagement/managedDevices?`$filter=contains(deviceName,'$safe')&`$select=id,deviceName,operatingSystem,complianceState&`$top=10" -Beta
            if ($deviceResponse.value) {
                $allResults.Devices = @($deviceResponse.value)
            }

            # Search apps
            $appResponse = Invoke-InTUIGraphRequest -Uri "/deviceAppManagement/mobileApps?`$filter=contains(displayName,'$safe')&`$select=id,displayName&`$top=10" -Beta
            if ($appResponse.value) {
                $allResults.Apps = @($appResponse.value)
            }

            # Search users
            $userResponse = Invoke-InTUIGraphRequest -Uri "/users?`$filter=startswith(displayName,'$safe') or startswith(userPrincipalName,'$safe')&`$select=id,displayName,userPrincipalName&`$top=10"
            if ($userResponse.value) {
                $allResults.Users = @($userResponse.value)
            }

            # Search groups
            $groupResponse = Invoke-InTUIGraphRequest -Uri "/groups?`$filter=startswith(displayName,'$safe')&`$select=id,displayName,description&`$top=10"
            if ($groupResponse.value) {
                $allResults.Groups = @($groupResponse.value)
            }

            $allResults
        }

        $totalCount = $results.Devices.Count + $results.Apps.Count + $results.Users.Count + $results.Groups.Count

        if ($totalCount -eq 0) {
            Show-InTUIWarning "No results found for '$searchTerm'."
            Read-InTUIKey
            continue
        }

        Write-InTUILog -Message "Search completed" -Context @{
            SearchTerm = $searchTerm
            Devices = $results.Devices.Count
            Apps = $results.Apps.Count
            Users = $results.Users.Count
            Groups = $results.Groups.Count
        }

        # Build results menu
        $resultChoices = @()
        $resultMap = @{}

        # Add devices
        if ($results.Devices.Count -gt 0) {
            $resultChoices += "[blue]--- Devices ($($results.Devices.Count)) ---[/]"
            foreach ($device in $results.Devices) {
                $compColor = Get-InTUIComplianceColor -State $device.complianceState
                $choice = "[blue]D[/] [white]$($device.deviceName)[/] [grey]| $($device.operatingSystem) |[/] [$compColor]$($device.complianceState)[/]"
                $resultChoices += $choice
                $resultMap[$choice] = @{ Type = 'Device'; Id = $device.id; Name = $device.deviceName }
            }
        }

        # Add apps
        if ($results.Apps.Count -gt 0) {
            $resultChoices += "[green]--- Apps ($($results.Apps.Count)) ---[/]"
            foreach ($app in $results.Apps) {
                $appType = Get-InTUIAppTypeFriendlyName -ODataType $app.'@odata.type'
                $choice = "[green]A[/] [white]$(ConvertTo-InTUISafeMarkup -Text $app.displayName)[/] [grey]| $appType[/]"
                $resultChoices += $choice
                $resultMap[$choice] = @{ Type = 'App'; Id = $app.id; Name = $app.displayName }
            }
        }

        # Add users
        if ($results.Users.Count -gt 0) {
            $resultChoices += "[yellow]--- Users ($($results.Users.Count)) ---[/]"
            foreach ($user in $results.Users) {
                $choice = "[yellow]U[/] [white]$(ConvertTo-InTUISafeMarkup -Text $user.displayName)[/] [grey]| $($user.userPrincipalName)[/]"
                $resultChoices += $choice
                $resultMap[$choice] = @{ Type = 'User'; Id = $user.id; Name = $user.displayName }
            }
        }

        # Add groups
        if ($results.Groups.Count -gt 0) {
            $resultChoices += "[cyan]--- Groups ($($results.Groups.Count)) ---[/]"
            foreach ($group in $results.Groups) {
                $desc = if ($group.description) { $group.description.Substring(0, [Math]::Min(30, $group.description.Length)) } else { 'No description' }
                $choice = "[cyan]G[/] [white]$(ConvertTo-InTUISafeMarkup -Text $group.displayName)[/] [grey]| $desc[/]"
                $resultChoices += $choice
                $resultMap[$choice] = @{ Type = 'Group'; Id = $group.id; Name = $group.displayName }
            }
        }

        $resultChoices += '─────────────'
        $resultChoices += 'New Search'
        $resultChoices += 'Back to Home'

        Show-InTUIStatusBar -Total $totalCount -Showing $totalCount -FilterText "Search: $searchTerm"

        $selection = Show-InTUIMenu -Title "[blue]Search Results[/]" -Choices $resultChoices -PageSize 20

        switch ($selection) {
            'New Search' {
                continue
            }
            'Back to Home' {
                $exitSearch = $true
            }
            '─────────────' {
                continue
            }
            default {
                # Skip header lines (not in resultMap)
                $selected = $resultMap[$selection]
                if (-not $selected) { continue }

                Write-InTUILog -Message "Search result selected" -Context @{
                    Type = $selected.Type
                    Id = $selected.Id
                    Name = $selected.Name
                }

                switch ($selected.Type) {
                    'Device' { Show-InTUIDeviceDetail -DeviceId $selected.Id }
                    'App'    { Show-InTUIAppDetail -AppId $selected.Id }
                    'User'   { Show-InTUIUserDetail -UserId $selected.Id }
                    'Group'  { Show-InTUIGroupDetail -GroupId $selected.Id }
                }
            }
        }
    }
}