Collectors/Applications.ps1

function Get-AerApplications {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory)] [string[]] $SubscriptionIds,
        [Parameter(Mandatory)]            $SubscriptionMap
    )

    $subLookup = @{}
    if ($SubscriptionMap -is [hashtable]) {
        $subLookup = $SubscriptionMap
    } elseif ($SubscriptionMap) {
        $SubscriptionMap.PSObject.Properties | ForEach-Object { $subLookup[$_.Name] = $_.Value }
    }

    # Static type → label/category map (microsoft.web/sites is resolved by kind below)
    $staticMap = @{
        'microsoft.web/serverfarms'                   = @{ Label = 'App Service Plan';         Category = 'Web / App Service' }
        'microsoft.web/hostingenvironments'           = @{ Label = 'App Service Environment';   Category = 'Web / App Service' }
        'microsoft.web/staticsites'                   = @{ Label = 'Static Web App';            Category = 'Web / App Service' }
        'microsoft.logic/workflows'                   = @{ Label = 'Logic App (Consumption)';   Category = 'Functions & Logic' }
        'microsoft.containerservice/managedclusters'  = @{ Label = 'Azure Kubernetes Service';  Category = 'Containers' }
        'microsoft.app/containerapps'                 = @{ Label = 'Container Apps';            Category = 'Containers' }
        'microsoft.app/managedenvironments'           = @{ Label = 'Container Apps Environment'; Category = 'Containers' }
        'microsoft.containerinstance/containergroups' = @{ Label = 'Container Instances';        Category = 'Containers' }
        'microsoft.containerregistry/registries'      = @{ Label = 'Container Registry';         Category = 'Containers' }
        'microsoft.servicefabric/clusters'            = @{ Label = 'Service Fabric';             Category = 'Containers' }
        'microsoft.apimanagement/service'             = @{ Label = 'API Management';             Category = 'API & Integration' }
    }
    function Classify($type, $kind) {
        if ($type -eq 'microsoft.web/sites') {
            $k = "$kind".ToLower()
            if ($k -match 'workflowapp') { return @{ Label = 'Logic App (Standard)';   Category = 'Functions & Logic' } }
            if ($k -match 'functionapp') { return @{ Label = 'Function App';            Category = 'Functions & Logic' } }
            if ($k -match 'container')   { return @{ Label = 'Web App for Containers';   Category = 'Web / App Service' } }
            return @{ Label = 'Web App'; Category = 'Web / App Service' }
        }
        return $staticMap[$type]
    }

    $types = @($staticMap.Keys) + 'microsoft.web/sites'
    $typeList = "'" + ($types -join "','") + "'"
    $query = @"
resources
| where type in~ ($typeList)
| project id, name, type = tolower(type), subscriptionId, resourceGroup, location,
          acctKind = tostring(kind),
          skuTier = tostring(sku.tier),
          kubeVersion = tostring(properties.kubernetesVersion),
          tags
"@


    $rows = @()
    try { $rows = Invoke-AerArgQuery -SubscriptionIds $SubscriptionIds -Query $query }
    catch { Write-Warning "[Applications.resources] $($_.Exception.Message)" }

    $byType = @{}; $labelCat = @{}; $byCat = @{}; $byLoc = @{}; $aksVer = @{}; $planTier = @{}

    foreach ($r in $rows) {
        $meta = Classify $r.type $r.acctKind
        if (-not $meta) { continue }
        $label = $meta.Label; $cat = $meta.Category

        $byType[$label]   = ([int]($byType[$label] ?? 0)) + 1
        $labelCat[$label] = $cat
        $byCat[$cat]      = ([int]($byCat[$cat] ?? 0)) + 1
        $loc = if ($r.location) { $r.location } else { '—' }
        $byLoc[$loc]      = ([int]($byLoc[$loc] ?? 0)) + 1

        if ($r.type -eq 'microsoft.containerservice/managedclusters' -and $r.kubeVersion) {
            $v = (($r.kubeVersion -split '\.')[0..1]) -join '.'
            $aksVer[$v] = ([int]($aksVer[$v] ?? 0)) + 1
        } elseif ($r.type -eq 'microsoft.web/serverfarms') {
            $tier = if ($r.skuTier) { $r.skuTier } else { 'Unknown' }
            $planTier[$tier] = ([int]($planTier[$tier] ?? 0)) + 1
        }
    }

    $catOrder = @('Web / App Service', 'Functions & Logic', 'Containers', 'API & Integration')
    $byCategory = foreach ($c in $catOrder) { [pscustomobject]@{ Category = $c; Count = [int]($byCat[$c] ?? 0) } }

    $byTypeList = $byType.GetEnumerator() | Sort-Object Value -Descending |
        ForEach-Object { [pscustomobject]@{ Label = $_.Key; Category = $labelCat[$_.Key]; Count = [int]$_.Value } }
    $byLocation = $byLoc.GetEnumerator() | Sort-Object Value -Descending | Select-Object -First 10 |
        ForEach-Object { [pscustomobject]@{ Region = $_.Key; Count = [int]$_.Value } }
    $aksByVersion = $aksVer.GetEnumerator() | Sort-Object Name -Descending |
        ForEach-Object { [pscustomobject]@{ Version = $_.Key; Count = [int]$_.Value } }
    $plansByTier = $planTier.GetEnumerator() | Sort-Object Value -Descending |
        ForEach-Object { [pscustomobject]@{ Tier = $_.Key; Count = [int]$_.Value } }

    return [pscustomobject]@{
        TotalServices = ($rows | Measure-Object).Count
        Web           = [int]($byCat['Web / App Service'] ?? 0)
        Functions     = [int]($byCat['Functions & Logic'] ?? 0)
        Containers    = [int]($byCat['Containers'] ?? 0)
        Integration   = [int]($byCat['API & Integration'] ?? 0)
        Aks           = [int]($byType['Azure Kubernetes Service'] ?? 0)
        DistinctTypes = @($byTypeList).Count
        ByCategory    = @($byCategory)
        ByType        = @($byTypeList)
        ByLocation    = @($byLocation)
        AksByVersion  = @($aksByVersion)
        PlansByTier   = @($plansByTier)
    }
}