Private/storage-functions.ps1

function Show-UnusedPVCs {
    param(
        [int]$PageSize = 10,
        [switch]$Html  # If specified, return an HTML table
    )

    if (-not $Global:MakeReport -and -not $Html) { Clear-Host }
    Write-Host "`n[💾 Unused Persistent Volume Claims]" -ForegroundColor Cyan
    Write-Host -NoNewline "`n🤖 Fetching PVC Data..." -ForegroundColor Yellow

    # Capture raw kubectl output
    $pvcsRaw = kubectl get pvc --all-namespaces -o json 2>&1 | Out-String

    # "No resources found" before JSON parse
    if ($pvcsRaw -match "No resources found") {
        Write-Host "`r🤖 ✅ No PVCs found in the cluster." -ForegroundColor Green
        if ($Global:MakeReport -and -not $Html) {
            Write-ToReport "`n[💾 Unused Persistent Volume Claims]`n"
            Write-ToReport "✅ No PVCs found in the cluster."
        }
        if (-not $Global:MakeReport -and -not $Html) {
            Read-Host "🤖 Press Enter to return to the menu"
        }
        if ($Html) { return "<p><strong>✅ No PVCs found in the cluster.</strong></p>" }
        return
    }

    # Convert JSON
    try {
        $pvcsJson = $pvcsRaw | ConvertFrom-Json
        $pvcs = if ($pvcsJson.PSObject.Properties['items']) { $pvcsJson.items } else { @() }
    }
    catch {
        Write-Host "`r🤖 ❌ Failed to parse JSON from kubectl output." -ForegroundColor Red
        if ($Global:MakeReport -and -not $Html) {
            Write-ToReport "`n[💾 Unused Persistent Volume Claims]`n"
            Write-ToReport "❌ Failed to parse JSON from kubectl output."
        }
        if (-not $Global:MakeReport -and -not $Html) {
            Read-Host "🤖 Press Enter to return to the menu"
        }
        if ($Html) { return "<p><strong>❌ Failed to parse JSON from kubectl output.</strong></p>" }
        return
    }

    # Ensure array
    if ($pvcs -isnot [System.Array]) { $pvcs = @($pvcs) }

    # Check if PVCs exist
    if ($pvcs.Count -eq 0) {
        Write-Host "`r🤖 ✅ No unused PVCs found." -ForegroundColor Green
        if ($Global:MakeReport -and -not $Html) {
            Write-ToReport "`n[💾 Unused Persistent Volume Claims]`n"
            Write-ToReport "✅ No unused PVCs found."
        }
        if (-not $Global:MakeReport -and -not $Html) {
            Read-Host "🤖 Press Enter to return to the menu"
        }
        if ($Html) { return "<p><strong>✅ No unused PVCs found.</strong></p>" }
        return
    }

    Write-Host "`r🤖 ✅ PVCs fetched. (Total: $($pvcs.Count))" -ForegroundColor Green
    Write-Host -NoNewline "`n🤖 Fetching Pod Data..." -ForegroundColor Yellow

    # Fetch all Pods
    $pods = kubectl get pods --all-namespaces -o json | ConvertFrom-Json | Select-Object -ExpandProperty items
    if (-not $pods) {
        Write-Host "`r🤖 ❌ Failed to fetch Pod data." -ForegroundColor Red
        if ($Global:MakeReport -and -not $Html) {
            Write-ToReport "`n[💾 Unused Persistent Volume Claims]`n"
            Write-ToReport "❌ Failed to fetch Pod data."
        }
        if (-not $Global:MakeReport -and -not $Html) {
            Read-Host "🤖 Press Enter to return to the menu"
        }
        if ($Html) { return "<p><strong>❌ Failed to fetch Pod data.</strong></p>" }
        return
    }

    Write-Host "`r🤖 ✅ Pods fetched. (Total: $($pods.Count))" -ForegroundColor Green

    Write-Host "`n🤖 Analyzing PVC usage..." -ForegroundColor Yellow

    # Gather attached PVCs from pod volumes
    $attachedPVCs = $pods |
    ForEach-Object { $_.spec.volumes | Where-Object { $_.persistentVolumeClaim } } |
    Select-Object -ExpandProperty persistentVolumeClaim

    # Filter out any that appear in attachedPVCs
    $unusedPVCs = $pvcs | Where-Object { $_.metadata.name -notin $attachedPVCs.name }
    $totalPVCs = $unusedPVCs.Count

    if ($totalPVCs -eq 0) {
        Write-Host "`r🤖 ✅ No unused PVCs found." -ForegroundColor Green
        if ($Global:MakeReport -and -not $Html) {
            Write-ToReport "`n[💾 Unused Persistent Volume Claims]`n"
            Write-ToReport "✅ No unused PVCs found."
        }
        if (-not $Global:MakeReport -and -not $Html) {
            Read-Host "🤖 Press Enter to return to the menu"
        }
        if ($Html) { return "<p><strong>✅ No unused PVCs found.</strong></p>" }
        return
    }

    Write-Host "`r🤖 ✅ PVC usage analyzed. ($totalPVCs unused PVCs detected)" -ForegroundColor Green

    # If -Html, return an HTML table
    if ($Html) {
        $tableData = foreach ($pvc in $unusedPVCs) {
            [PSCustomObject]@{
                Namespace = $pvc.metadata.namespace
                PVC       = $pvc.metadata.name
                Storage   = $pvc.spec.resources.requests.storage
            }
        }

        $htmlTable = $tableData |
        ConvertTo-Html -Fragment -Property Namespace, PVC, Storage -PreContent "<h2>Unused Persistent Volume Claims</h2>" |
        Out-String

        # Insert note about total
        $htmlTable = "<p><strong>⚠️ Total Unused PVCs Found:</strong> $totalPVCs</p>" + $htmlTable
        return $htmlTable
    }

    # If in report mode (no -Html)
    if ($Global:MakeReport) {
        Write-ToReport "`n[💾 Unused Persistent Volume Claims]`n"
        Write-ToReport "⚠️ Total Unused PVCs Found: $totalPVCs"
        Write-ToReport "-------------------------------------------------"

        $tableData = @()
        foreach ($pvc in $unusedPVCs) {
            $tableData += [PSCustomObject]@{
                Namespace = $pvc.metadata.namespace
                PVC       = $pvc.metadata.name
                Storage   = $pvc.spec.resources.requests.storage
            }
        }

        $tableString = $tableData | Format-Table Namespace, PVC, Storage -AutoSize | Out-String
        Write-ToReport $tableString
        return
    }

    # Otherwise, pagination
    $currentPage = 0
    $totalPages = [math]::Ceiling($totalPVCs / $PageSize)

    do {
        Clear-Host
        Write-Host "`n[💾 Unused Persistent Volume Claims - Page $($currentPage + 1) of $totalPages]" -ForegroundColor Cyan

        $msg = @(
            "🤖 Persistent Volume Claims (PVCs) reserve storage in your cluster.",
            "",
            "📌 This check identifies PVCs that are NOT attached to any Pod.",
            " - Unused PVCs may indicate abandoned or uncleaned storage.",
            " - Storage resources remain allocated until PVCs are deleted.",
            "",
            "⚠️ Review unused PVCs before deletion to avoid accidental data loss.",
            "",
            "⚠️ Total Unused PVCs Found: $totalPVCs"
        )
        if ($currentPage -eq 0) {
            Write-SpeechBubble -msg $msg -color "Cyan" -icon "🤖" -lastColor "Red" -delay 50 # first page only
        }

        $startIndex = $currentPage * $PageSize
        $endIndex = [math]::Min($startIndex + $PageSize, $totalPVCs)

        $tableData = @()
        for ($i = $startIndex; $i -lt $endIndex; $i++) {
            $pvc = $unusedPVCs[$i]
            $tableData += [PSCustomObject]@{
                Namespace = $pvc.metadata.namespace
                PVC       = $pvc.metadata.name
                Storage   = $pvc.spec.resources.requests.storage
            }
        }

        if ($tableData) {
            $tableData | Format-Table Namespace, PVC, Storage -AutoSize
        }

        $newPage = Show-Pagination -currentPage $currentPage -totalPages $totalPages
        if ($newPage -eq -1) { break }
        $currentPage = $newPage

    } while ($true)
}