Private/Create-htmlReport.ps1

function Generate-K8sHTMLReport {
    param (
        [string]$outputPath,
        [string]$version = "v0.0.1",
        [string]$SubscriptionId,
        [string]$ResourceGroup,
        [string]$ClusterName,
        [switch]$aks,
        [switch]$ExcludeNamespaces,
        [object]$KubeData
    )

    function ConvertToCollapsible {
        param(
            [string]$Id,
            [string]$defaultText,
            [string]$content
        )
      
        @"
<div class="collapsible-container" id='$Id'>
<details style='margin:10px 0;'>
<summary style='font-size:16px; cursor:pointer; color:#0071FF; font-weight:bold;'>$defaultText</summary>
<div style='padding-top: 15px;'>
  $content
</div>
</details>
</div>
"@

    }

    if (Test-Path $outputPath) {
        Remove-Item $outputPath -Force
    }

     # Path to report-scripts.js in the module directory
     $jsPath = Join-Path $PSScriptRoot "html/report-scripts.js"

     # Read the JavaScript content
     if (Test-Path $jsPath) {
         $jsContent = Get-Content -Path $jsPath -Raw
     } else {
         $jsContent = "// Error: report-scripts.js not found at $jsPath"
         Write-Warning "report-scripts.js not found at $jsPath. HTML features may not work."
     }

    Write-Host "`n[🌐 Cluster Summary]" -ForegroundColor Cyan
    Write-Host -NoNewline "`n🤖 Fetching Cluster Information..." -ForegroundColor Yellow
    $clusterSummaryRaw = Show-ClusterSummary -Html -KubeData:$KubeData *>&1
    Write-Host "`r🤖 Cluster Information fetched. " -ForegroundColor Green

    if ($aks) {
        Write-Host -NoNewline "`n🤖 Running AKS Best Practices Checklist..." -ForegroundColor Cyan
        $aksBestPractices = Invoke-AKSBestPractices -SubscriptionId $SubscriptionId -ResourceGroup $ResourceGroup -ClusterName $ClusterName -Html -KubeData:$KubeData
        Write-Host "`r🤖 AKS Check Results fetched. " -ForegroundColor Green

        $aksPass = $aksBestPractices.Passed
        $aksFail = $aksBestPractices.Failed
        $aksTotal = $aksBestPractices.Total
        $aksScore = $aksBestPractices.Score
        $aksRating = $aksBestPractices.Rating
        $aksReportData = $aksBestPractices.Data

        $collapsibleAKSHtml = ConvertToCollapsible -Id "aksSummary" -defaultText "Show Findings" -content $aksReportData

        $ratingColorClass = switch ($aksRating) {
            "A" { "normal" }
            "B" { "warning" }
            "C" { "warning" }
            "D" { "critical" }
            "F" { "critical" }
            default { "unknown" }
        }

        $heroRatingHtml = @"
<h2>AKS Best Practices Summary</h2>
<div class="hero-metrics">
<div class="metric-card normal">✅ Passed: <strong>$aksPass</strong></div>
<div class="metric-card critical">❌ Failed: <strong>$aksFail</strong></div>
<div class="metric-card default">📊 Total Checks: <strong>$aksTotal</strong></div>
<div class="metric-card $ratingColorClass">🎯 Score: <strong>$aksScore%</strong></div>
<div class="metric-card $ratingColorClass">⭐ Rating: <strong>$aksRating</strong></div>
</div>
"@


        $aksHealthCheck = @"
<div class="container">
<h1 id="aks">AKS Best Practices Details</h1>
$heroRatingHtml
<h2 id="aksFindings">AKS Best Practices Results</h2>
<div class="table-container">
$collapsibleAKSHtml
</div>
</div>
"@


        $aksMenuItem = @"
<li class="nav-item"><a href="#aks"><span class="material-icons">verified</span> AKS Best Practices</a></li>
"@

    }

    $checks = @(
        @{ Id = "nodeConditions"; Cmd = { Show-NodeConditions -Html -PageSize 999 -ExcludeNamespaces:$ExcludeNamespaces -KubeData:$KubeData } },
        @{ Id = "nodeResources"; Cmd = { Show-NodeResourceUsage -Html -PageSize 999 -ExcludeNamespaces:$ExcludeNamespaces -KubeData:$KubeData } },
        @{ Id = "emptyNamespace"; Cmd = { Show-EmptyNamespaces -Html -PageSize 999 -ExcludeNamespaces:$ExcludeNamespaces -KubeData:$KubeData } },
        @{ Id = "resourceQuotas"; Cmd = { Check-ResourceQuotas -Html -PageSize 999 -ExcludeNamespaces:$ExcludeNamespaces -KubeData:$KubeData } },
        @{ Id = "namespaceLimitRanges"; Cmd = { Check-NamespaceLimitRanges -Html -PageSize 999 -ExcludeNamespaces:$ExcludeNamespaces -KubeData:$KubeData } },
        @{ Id = "daemonSetIssues"; Cmd = { Show-DaemonSetIssues -Html -PageSize 999 -ExcludeNamespaces:$ExcludeNamespaces -KubeData:$KubeData } },
        @{ Id = "HPA"; Cmd = { Check-HPAStatus -Html -PageSize 999 -ExcludeNamespaces:$ExcludeNamespaces -KubeData:$KubeData } },
        @{ Id = "missingResourceLimits"; Cmd = { Check-MissingResourceLimits -Html -PageSize 999 -ExcludeNamespaces:$ExcludeNamespaces -KubeData:$KubeData } },
        @{ Id = "PDB"; Cmd = { Check-PodDisruptionBudgets -Html -PageSize 999 -ExcludeNamespaces:$ExcludeNamespaces -KubeData:$KubeData } },
        @{ Id = "missingProbes"; Cmd = { Check-MissingHealthProbes -Html -PageSize 999 -ExcludeNamespaces:$ExcludeNamespaces -KubeData:$KubeData } },
        @{ Id = "podsRestart"; Cmd = { Show-PodsWithHighRestarts -Html -PageSize 999 -ExcludeNamespaces:$ExcludeNamespaces -KubeData:$KubeData } },
        @{ Id = "podLongRunning"; Cmd = { Show-LongRunningPods -Html -PageSize 999 -ExcludeNamespaces:$ExcludeNamespaces -KubeData:$KubeData } },
        @{ Id = "podFail"; Cmd = { Show-FailedPods -Html -PageSize 999 -ExcludeNamespaces:$ExcludeNamespaces -KubeData:$KubeData } },
        @{ Id = "podPending"; Cmd = { Show-PendingPods -Html -PageSize 999 -ExcludeNamespaces:$ExcludeNamespaces -KubeData:$KubeData } },
        @{ Id = "crashloop"; Cmd = { Show-CrashLoopBackOffPods -Html -PageSize 999 -ExcludeNamespaces:$ExcludeNamespaces -KubeData:$KubeData } },
        @{ Id = "leftoverDebug"; Cmd = { Show-LeftoverDebugPods -Html -PageSize 999 -ExcludeNamespaces:$ExcludeNamespaces -KubeData:$KubeData } },
        @{ Id = "stuckJobs"; Cmd = { Show-StuckJobs -Html -PageSize 999 -ExcludeNamespaces:$ExcludeNamespaces -KubeData:$KubeData } },
        @{ Id = "jobFail"; Cmd = { Show-FailedJobs -Html -PageSize 999 -ExcludeNamespaces:$ExcludeNamespaces -KubeData:$KubeData } },
        @{ Id = "servicesWithoutEndpoints"; Cmd = { Show-ServicesWithoutEndpoints -Html -PageSize 999 -ExcludeNamespaces:$ExcludeNamespaces -KubeData:$KubeData } },
        @{ Id = "publicServices"; Cmd = { Check-PubliclyAccessibleServices -Html -PageSize 999 -ExcludeNamespaces:$ExcludeNamespaces -KubeData:$KubeData } },
        @{ Id = "unmountedPV"; Cmd = { Show-UnusedPVCs -Html -PageSize 999 -ExcludeNamespaces:$ExcludeNamespaces -KubeData:$KubeData } },
        @{ Id = "rbacMisconfig"; Cmd = { Check-RBACMisconfigurations -Html -PageSize 999 -ExcludeNamespaces:$ExcludeNamespaces -KubeData:$KubeData } },
        @{ Id = "rbacOverexposure"; Cmd = { Check-RBACOverexposure -Html -PageSize 999 -ExcludeNamespaces:$ExcludeNamespaces -KubeData:$KubeData } },
        @{ Id = "orphanedServiceAccounts"; Cmd = { Check-OrphanedServiceAccounts -Html -PageSize 999 -ExcludeNamespaces:$ExcludeNamespaces -KubeData:$KubeData } },
        @{ Id = "orphanedRoles"; Cmd = { Check-OrphanedRoles -Html -PageSize 999 -ExcludeNamespaces:$ExcludeNamespaces -KubeData:$KubeData } },
        @{ Id = "orphanedConfigMaps"; Cmd = { Check-OrphanedConfigMaps -Html -PageSize 999 -ExcludeNamespaces:$ExcludeNamespaces -KubeData:$KubeData } },
        @{ Id = "orphanedSecrets"; Cmd = { Check-OrphanedSecrets -Html -PageSize 999 -ExcludeNamespaces:$ExcludeNamespaces -KubeData:$KubeData } },
        @{ Id = "podsRoot"; Cmd = { Check-PodsRunningAsRoot -Html -PageSize 999 -ExcludeNamespaces:$ExcludeNamespaces -KubeData:$KubeData } },
        @{ Id = "privilegedContainers"; Cmd = { Check-PrivilegedContainers -Html -PageSize 999 -ExcludeNamespaces:$ExcludeNamespaces -KubeData:$KubeData } },
        @{ Id = "hostPidNet"; Cmd = { Check-HostPidAndNetwork -Html -PageSize 999 -ExcludeNamespaces:$ExcludeNamespaces -KubeData:$KubeData } },
        @{ Id = "eventSummary"; Cmd = { Show-KubeEvents -Html -PageSize 999 -KubeData:$KubeData } },
        @{ Id = "deploymentIssues"; Cmd = { Check-DeploymentIssues -Html -PageSize 999 -ExcludeNamespaces:$ExcludeNamespaces -KubeData:$KubeData } },
        @{ Id = "statefulSetIssues"; Cmd = { Check-StatefulSetIssues -Html -PageSize 999 -ExcludeNamespaces:$ExcludeNamespaces -KubeData:$KubeData } },
        @{ Id = "ingressHealth"; Cmd = { Check-IngressHealth -Html -PageSize 999 -ExcludeNamespaces:$ExcludeNamespaces -KubeData:$KubeData } }        
        )

    foreach ($check in $checks) {
        $html = & $check.Cmd
        if (-not $html) {
            $html = "<p>No data available for $($check.Id).</p>"
        }

        $pre = ""
        if ($html -match '^\s*<p>.*?</p>') {
            $pre = $matches[0]
            $html = $html -replace [regex]::Escape($pre), ""
        }
        elseif ($html -match '^\s*[^<]+$') {
            $lines = $html -split "`n", 2
            $pre = "<p>$($lines[0].Trim())</p>"
            $html = if ($lines.Count -gt 1) { $lines[1] } else { "" }
        }
        else {
            $pre = "<p>⚠️ $($check.Id) Report</p>"
        }

        $hasIssues = $html -match '<tr>.*?<td>.*?</td>.*?</tr>' -and $html -notmatch 'No data available'
        $recommendation = ""

        $noFindings = $pre -match '✅'

        if ($check.Id -in @("nodeConditions", "nodeResources")) {
            $warningsCount = 0
            if ($check.Id -eq "nodeConditions" -and $pre -match "Total Not Ready Nodes: (\d+)") {
                $warningsCount = [int]$matches[1]
            }
            elseif ($check.Id -eq "nodeResources" -and $pre -match "Total Resource Warnings Across All Nodes: (\d+)") {
                $warningsCount = [int]$matches[1]
            }
            $hasIssues = $warningsCount -ge 1
            $noFindings = $warningsCount -eq 0
            # Override noFindings for nodeConditions and nodeResources to always show the table
            if ($check.Id -in @("nodeConditions", "nodeResources")) {
                $noFindings = $false
            }
        }

        if ($hasIssues) {
            $recommendationText = switch ($check.Id) {
                "nodeConditions" {
                    @"
<div class="recommendation-content">
  <h4>🛠️ Fix Node Issues</h4>
  <ul>
      <li><strong>Check Node Status:</strong> Run <code>kubectl describe node <node-name></code> to inspect conditions like DiskPressure, MemoryPressure, or NotReady states.</li>
      <li><strong>Taints and Tolerations:</strong> If nodes are tainted, ensure pods have matching tolerations (<code>kubectl edit node <node-name></code> to remove unnecessary taints).</li>
      <li><strong>Resource Exhaustion:</strong> If nodes are overloaded, scale up the cluster (<code>az aks scale</code>) or evict pods to other nodes.</li>
      <li><strong>Logs:</strong> Check system logs via <code>kubectl logs -n kube-system</code> for kubelet or other issues.</li>
  </ul>
</div>
"@

                }
                "nodeResources" {
                    @"
<div class="recommendation-content">
  <h4>🛠️ Optimize Resource Usage</h4>
  <ul>
      <li><strong>Monitor Usage:</strong> Use <code>kubectl top nodes</code> to identify nodes with high CPU/memory usage (>80%).</li>
      <li><strong>Scale Nodes:</strong> Add more nodes if capacity is consistently exceeded (<code>az aks nodepool add</code> for AKS).</li>
      <li><strong>Pod Limits:</strong> Set resource requests/limits in pod specs to prevent overconsumption (e.g., <code>resources: { requests: { cpu: "100m" } }</code>).</li>
      <li><strong>Horizontal Scaling:</strong> Deploy a HorizontalPodAutoscaler (<code>kubectl autoscale</code>) for workloads causing spikes.</li>
      <li><strong>Eviction:</strong> Manually reschedule pods (<code>kubectl drain <node-name></code>) if a node is overloaded.</li>
  </ul>
</div>
"@

                }
                "emptyNamespace" {
                    @"
<div class="recommendation-content">
  <h4>🛠️ Clean Up Empty Namespaces</h4>
  <ul>
      <li><strong>Verify Usage:</strong> Check if namespaces are truly unused with <code>kubectl get all -n <namespace></code>.</li>
      <li><strong>Delete:</strong> Remove empty namespaces with <code>kubectl delete ns <namespace></code> to reduce clutter.</li>
      <li><strong>Documentation:</strong> If retained, document their purpose in a ConfigMap or team wiki to avoid confusion.</li>
      <li><strong>Automation:</strong> Consider a cronjob to periodically clean up unused namespaces.</li>
  </ul>
</div>
"@

                }
                "resourceQuotas" {
@"
<div class="recommendation-content">
  <h4>🛠️ Set ResourceQuotas</h4>
  <ul>
      <li><strong>Define:</strong> Create ResourceQuota objects with limits on CPU, memory, and pods per namespace.</li>
      <li><strong>Example:</strong>
<pre><code>apiVersion: v1
kind: ResourceQuota
metadata:
  name: compute-resources
spec:
  hard:
    pods: "10"
    requests.cpu: "1"
    requests.memory: 1Gi
    limits.cpu: "2"
    limits.memory: 2Gi
</code></pre></li>
      <li><strong>Scope:</strong> Apply different quotas per environment (e.g., dev vs prod).</li>
      <li><strong>Monitor:</strong> Use <code>kubectl describe quota -n <namespace></code> to see usage.</li>
  </ul>
</div>
"@

                }
                "namespaceLimitRanges" {
@"
<div class="recommendation-content">
  <h4>🛠️ Add LimitRanges</h4>
  <ul>
      <li><strong>Define Defaults:</strong> Set default requests and limits per container using LimitRange.</li>
      <li><strong>Example:</strong>
<pre><code>apiVersion: v1
kind: LimitRange
metadata:
  name: limits
spec:
  limits:
  - default:
      cpu: "500m"
      memory: "512Mi"
    defaultRequest:
      cpu: "250m"
      memory: "256Mi"
    type: Container
</code></pre></li>
      <li><strong>Purpose:</strong> Prevent pods from running without resource caps or defaults.</li>
      <li><strong>Apply:</strong> <code>kubectl apply -f limitrange.yaml -n <namespace></code></li>
  </ul>
</div>
"@

                }
                "daemonSetIssues" {
                    @"
<div class="recommendation-content">
  <h4>🛠️ Resolve DaemonSet Issues</h4>
  <ul>
      <li><strong>Inspect Logs:</strong> Check pod logs with <code>kubectl logs -l <selector> -n <namespace></code> for errors.</li>
      <li><strong>Node Affinity:</strong> Ensure DaemonSet spec matches node conditions (<code>kubectl describe ds <name></code>).</li>
      <li><strong>Tolerations:</strong> Add tolerations if nodes are tainted (<code>spec.template.spec.tolerations</code>).</li>
      <li><strong>Rollout:</strong> Restart rollout if stuck (<code>kubectl rollout restart ds <name></code>).</li>
  </ul>
</div>
"@

                }
                "deployments" {
@"
<div class="recommendation-content">
  <h4>🛠️ Fix Deployment Issues</h4>
  <ul>
      <li><strong>Rollout Status:</strong> Use <code>kubectl rollout status deploy <name> -n <namespace></code> to check for rollout problems.</li>
      <li><strong>Unavailable Pods:</strong> If replicas are unavailable, inspect pod events and logs for failures.</li>
      <li><strong>Strategy:</strong> Consider using <code>RollingUpdate</code> with a proper <code>maxUnavailable</code> setting to avoid disruption.</li>
      <li><strong>Recreate:</strong> Use <code>kubectl rollout restart deploy <name></code> if stuck or hanging.</li>
  </ul>
</div>
"@

                }
                "statefulsets" {
@"
<div class="recommendation-content">
  <h4>🛠️ Review StatefulSet Health</h4>
  <ul>
      <li><strong>Pod Status:</strong> Check pod readiness and init status with <code>kubectl get pods -l app=<label> -n <namespace></code>.</li>
      <li><strong>Persistent Volumes:</strong> Verify PVCs are properly bound and mounted.</li>
      <li><strong>Pod Ordinality:</strong> StatefulSets start pods in order. A stuck pod blocks the rest—check logs of the first pod.</li>
      <li><strong>Headless Service:</strong> Ensure a headless service is defined for network identity.</li>
  </ul>
</div>
"@

                }
                "HPA" { @"
<div class='recommendation-content'>
  <h4>🛠️ Configure Horizontal Pod Autoscalers</h4>
  <ul>
    <li><strong>Enable Scaling:</strong> Apply HPA to workloads using <code>kubectl autoscale deploy <name> --min=1 --max=5 --cpu-percent=80</code>.</li>
    <li><strong>CPU/Memory Metrics:</strong> Ensure the metrics server is deployed and working correctly.</li>
    <li><strong>Custom Metrics:</strong> Use <code>external.metrics.k8s.io</code> or <code>custom.metrics.k8s.io</code> for advanced autoscaling logic.</li>
    <li><strong>Validation:</strong> Monitor scaling events with <code>kubectl describe hpa <name></code>.</li>
  </ul>
</div>
"@
 
                }
                "missingResourceLimits" { @"
<div class='recommendation-content'>
  <h4>🛠️ Add Resource Requests and Limits</h4>
  <ul>
    <li><strong>Define Requests:</strong> Use <code>resources.requests</code> for <code>cpu</code> and <code>memory</code> to guarantee minimum resources.</li>
    <li><strong>Define Limits:</strong> Use <code>resources.limits</code> to cap maximum usage for <code>cpu</code> and <code>memory</code>.</li>
    <li><strong>Example:</strong>
      <pre><code>resources:
  requests:
    cpu: "250m"
    memory: "128Mi"
  limits:
    cpu: "500m"
    memory: "256Mi"</code></pre>
    </li>
    <li><strong>Why:</strong> Avoids resource contention, supports fair scheduling, and prevents overcommitment.</li>
    <li><strong>Policy Tips:</strong> Use <code>LimitRanges</code> and admission policies to apply defaults or enforce constraints.</li>
  </ul>
</div>
"@

                }
                "PDB" { @"
<div class='recommendation-content'>
  <h4>🛠️ Improve PDB Coverage</h4>
  <ul>
    <li><strong>Apply PDBs:</strong> Create PDBs for all critical workloads to control voluntary disruptions.</li>
    <li><strong>Avoid Weak PDBs:</strong> Don't set <code>minAvailable: 0</code> or <code>maxUnavailable: 100%</code>—they offer no protection.</li>
    <li><strong>Label Matching:</strong> Verify selectors actually match pods (<code>spec.selector.matchLabels</code>).</li>
    <li><strong>Dry Run:</strong> Use <code>kubectl get pdb -o wide</code> to confirm expected pod count.</li>
  </ul>
</div>
"@
 
                }
                "missingProbes" { @"
<div class='recommendation-content'>
  <h4>🛠️ Add Health Probes</h4>
  <ul>
    <li><strong>Readiness Probes:</strong> Signal when the container is ready to serve traffic.</li>
    <li><strong>Liveness Probes:</strong> Detect deadlocked or crashed apps. Example: <code>httpGet</code> or <code>exec</code>.</li>
    <li><strong>Startup Probes:</strong> Useful for slow-starting apps to avoid premature kills.</li>
    <li><strong>Validation:</strong> Test probe behavior with <code>kubectl describe pod <name></code>.</li>
  </ul>
</div>
"@
 
                }
                "podsRestart" {
                    @"
<div class="recommendation-content">
  <h4>🛠️ Fix High Restart Pods</h4>
  <ul>
      <li><strong>Logs:</strong> Review pod logs (<code>kubectl logs <pod-name> -n <namespace></code>) to identify crash reasons.</li>
      <li><strong>Resources:</strong> Increase CPU/memory limits in pod spec if resource starvation is suspected.</li>
      <li><strong>Liveness Probes:</strong> Adjust or remove overly strict liveness probes causing restarts (<code>spec.containers.livenessProbe</code>).</li>
      <li><strong>App Debugging:</strong> Fix application code if it’s exiting unexpectedly (check exit codes).</li>
  </ul>
</div>
"@

                }
                "podLongRunning" {
                    @"
<div class="recommendation-content">
  <h4>🛠️ Handle Long-Running Pods</h4>
  <ul>
      <li><strong>Verify Intent:</strong> Confirm if pods should run indefinitely (<code>kubectl describe pod <pod-name></code>).</li>
      <li><strong>Stuck Jobs:</strong> If from a Job, check job status (<code>kubectl describe job <job-name></code>) and delete if stuck (<code>kubectl delete pod <pod-name></code>).</li>
      <li><strong>Timeouts:</strong> Add pod disruption budgets or termination grace periods to manage lifecycle.</li>
      <li><strong>Monitoring:</strong> Set up alerts for pods exceeding expected runtime.</li>
  </ul>
</div>
"@

                }
                "podFail" {
                    @"
<div class="recommendation-content">
  <h4>🛠️ Resolve Failed Pods</h4>
  <ul>
      <li><strong>Events:</strong> Check events with <code>kubectl describe pod <pod-name> -n <namespace></code> for failure reasons.</li>
      <li><strong>Logs:</strong> Inspect logs (<code>kubectl logs <pod-name> --previous</code>) for crash details.</li>
      <li><strong>Exit Codes:</strong> Decode exit codes (e.g., 1 for app error, 137 for OOM) and adjust app or resources.</li>
      <li><strong>Restart Policy:</strong> Ensure pod spec’s restartPolicy is appropriate (<code>Never</code> vs <code>OnFailure</code>).</li>
  </ul>
</div>
"@

                }
                "podPending" {
                    @"
<div class="recommendation-content">
  <h4>🛠️ Fix Pending Pods</h4>
  <ul>
      <li><strong>Resources:</strong> Check cluster capacity (<code>kubectl top nodes</code>) and quotas (<code>kubectl get resourcequota -n <namespace></code>).</li>
      <li><strong>Taints:</strong> Add tolerations if nodes are tainted (<code>kubectl edit pod <pod-name></code>).</li>
      <li><strong>Scheduling:</strong> Review node affinity/selectors (<code>kubectl describe pod <pod-name></code>).</li>
      <li><strong>Scale:</strong> Add nodes if cluster is at capacity (<code>az aks scale</code>).</li>
  </ul>
</div>
"@

                }
                "crashloop" {
                    @"
<div class="recommendation-content">
  <h4>🛠️ Fix CrashLoopBackOff Pods</h4>
  <ul>
      <li><strong>Logs:</strong> Check logs (<code>kubectl logs <pod-name> -n <namespace></code>) for crash causes.</li>
      <li><strong>Resources:</strong> Increase requests/limits if OOMKilled (<code>spec.containers.resources</code>).</li>
      <li><strong>Probes:</strong> Adjust readiness/liveness probes if too aggressive (<code>spec.containers.livenessProbe</code>).</li>
      <li><strong>App Fix:</strong> Debug app code for unhandled exceptions or misconfiguration.</li>
  </ul>
</div>
"@

                }
                "leftoverDebug" {
                    @"
<div class="recommendation-content">
  <h4>🛠️ Remove Debug Pods</h4>
  <ul>
      <li><strong>Identify:</strong> Confirm pods are debug-related (<code>kubectl describe pod <pod-name></code>).</li>
      <li><strong>Delete:</strong> Remove with <code>kubectl delete pod <pod-name> -n <namespace></code>).</li>
      <li><strong>Policy:</strong> Set TTL or cleanup scripts to auto-remove debug pods post-use.</li>
      <li><strong>Monitoring:</strong> Alert on lingering debug pods to prevent resource waste.</li>
  </ul>
</div>
"@

                }
                "stuckJobs" {
                    @"
<div class="recommendation-content">
  <h4>🛠️ Resolve Stuck Jobs</h4>
  <ul>
      <li><strong>Status:</strong> Inspect job with <code>kubectl describe job <job-name></code> for pod failures.</li>
      <li><strong>Pods:</strong> Check pod logs (<code>kubectl logs -l job-name=<job-name></code>) for errors.</li>
      <li><strong>Delete:</strong> Remove stuck jobs (<code>kubectl delete job <job-name></code>) if unresolvable.</li>
      <li><strong>Backoff:</strong> Adjust <code>spec.backoffLimit</code> if retries are exhausted too quickly.</li>
  </ul>
</div>
"@

                }
                "jobFail" {
                    @"
<div class="recommendation-content">
  <h4>🛠️ Fix Failed Jobs</h4>
  <ul>
      <li><strong>Logs:</strong> Review pod logs (<code>kubectl logs -l job-name=<job-name></code>) for failure details.</li>
      <li><strong>Spec:</strong> Check job spec (<code>kubectl get job <job-name> -o yaml</code>) for misconfiguration.</li>
      <li><strong>Resources:</strong> Ensure sufficient CPU/memory (<code>spec.template.spec.resources</code>).</li>
      <li><strong>Retry:</strong> Increase <code>spec.backoffLimit</code> or fix underlying app issues.</li>
  </ul>
</div>
"@

                }
                "servicesWithoutEndpoints" {
                    @"
<div class="recommendation-content">
  <h4>🛠️ Fix Services Without Endpoints</h4>
  <ul>
      <li><strong>Selectors:</strong> Verify service selectors match pod labels (<code>kubectl describe svc <svc-name></code>).</li>
      <li><strong>Pods:</strong> Deploy missing pods or fix pod failures (<code>kubectl get pods -l <selector></code>).</li>
      <li><strong>Network:</strong> Ensure network policies aren’t blocking endpoints.</li>
      <li><strong>Debug:</strong> Use <code>kubectl get endpoints <svc-name></code> to confirm endpoint creation.</li>
  </ul>
</div>
"@

                }
                "publicServices" {
                    @"
<div class="recommendation-content">
  <h4>🛠️ Secure Public Services</h4>
  <ul>
      <li><strong>Check Exposure:</strong> List services with <code>kubectl get svc -A | grep LoadBalancer</code>.</li>
      <li><strong>Restrict:</strong> Apply network policies to limit access (<code>kubectl apply -f policy.yaml</code>).</li>
      <li><strong>Internal:</strong> Use <code>service.beta.kubernetes.io/azure-load-balancer-internal: "true"</code> for AKS.</li>
      <li><strong>Review:</strong> Audit if public access is intentional or reduce scope.</li>
  </ul>
</div>
"@

                }
                "ingress" {
@"
<div class="recommendation-content">
  <h4>🛠️ Validate Ingress Resources</h4>
  <ul>
      <li><strong>Backend Services:</strong> Verify Ingress routes to services with healthy endpoints.</li>
      <li><strong>Annotations:</strong> Confirm correct ingress class or controller annotations.</li>
      <li><strong>TLS:</strong> Use <code>cert-manager</code> or secrets to configure valid TLS certs.</li>
      <li><strong>Check Errors:</strong> Look for HTTP 404s, 502s or connection errors in the ingress controller logs.</li>
  </ul>
</div>
"@

                }
                "unmountedPV" {
                    @"
<div class="recommendation-content">
  <h4>🛠️ Handle Unmounted PVs</h4>
  <ul>
      <li><strong>Verify:</strong> Check PVC status (<code>kubectl get pvc -A</code>) and pod mounts.</li>
      <li><strong>Reclaim:</strong> Delete unused PVCs (<code>kubectl delete pvc <pvc-name> -n <namespace></code>).</li>
      <li><strong>Reattach:</strong> Mount to a pod if needed (<code>spec.volumes</code> in pod spec).</li>
      <li><strong>Cleanup:</strong> Set reclaim policy to <code>Delete</code> if no longer needed (<code>kubectl edit pv</code>).</li>
  </ul>
</div>
"@

                }
                "rbacMisconfig" {
                    @"
<div class="recommendation-content">
  <h4>🛠️ Fix RBAC Misconfigurations</h4>
  <ul>
      <li><strong>Audit:</strong> List bindings (<code>kubectl get clusterrolebinding,rolebinding -A</code>).</li>
      <li><strong>Subjects:</strong> Add missing subjects (<code>kubectl edit clusterrolebinding <name></code>).</li>
      <li><strong>Remove:</strong> Delete unused roles/bindings (<code>kubectl delete clusterrole <name></code>).</li>
      <li><strong>Test:</strong> Use <code>kubectl auth can-i</code> to verify permissions.</li>
  </ul>
</div>
"@

                }
                "rbacOverexposure" {
                    @"
<div class="recommendation-content">
  <h4>🛠️ Reduce RBAC Overexposure</h4>
  <ul>
      <li><strong>Audit:</strong> Check permissions (<code>kubectl auth can-i --list -A</code>).</li>
      <li><strong>Scope:</strong> Replace cluster-wide roles with namespace-specific ones (<code>kubectl create role</code>).</li>
      <li><strong>Least Privilege:</strong> Limit verbs/resources in role definitions.</li>
      <li><strong>Review:</strong> Regularly audit with tools like <code>rbac-tool</code> or <code>kubectl who-can</code>.</li>
  </ul>
</div>
"@

                }
                "orphanedConfigMaps" {
                    @"
<div class="recommendation-content">
  <h4>🛠️ Clean Up Orphaned ConfigMaps</h4>
  <ul>
      <li><strong>Verify:</strong> Check usage (<code>kubectl describe cm <name> -n <namespace></code>).</li>
      <li><strong>Delete:</strong> Remove unused ConfigMaps (<code>kubectl delete cm <name> -n <namespace></code>).</li>
      <li><strong>Documentation:</strong> Note purpose in annotations if retained.</li>
      <li><strong>Automation:</strong> Script cleanup for unused ConfigMaps.</li>
  </ul>
</div>
"@

                }
                "orphanedSecrets" {
                    @"
<div class="recommendation-content">
  <h4>🛠️ Handle Orphaned Secrets</h4>
  <ul>
      <li><strong>Check:</strong> Verify usage (<code>kubectl describe secret <name> -n <namespace></code>).</li>
      <li><strong>Delete:</strong> Remove unused Secrets (<code>kubectl delete secret <name> -n <namespace></code>).</li>
      <li><strong>Mount:</strong> Ensure Secrets are mounted or referenced if needed (<code>spec.volumes.secret</code>).</li>
      <li><strong>Security:</strong> Rotate if exposed and no longer used.</li>
  </ul>
</div>
"@

                }
                "podsRoot" {
                    @"
<div class="recommendation-content">
  <h4>🛠️ Secure Root Pods</h4>
  <ul>
      <li><strong>Config:</strong> Set <code>securityContext.runAsNonRoot: true</code> in pod spec.</li>
      <li><strong>User:</strong> Define <code>runAsUser: <non-zero-uid></code> to avoid root.</li>
      <li><strong>Verify:</strong> Check with <code>kubectl exec <pod-name> -- whoami</code>.</li>
      <li><strong>Policy:</strong> Enforce via PodSecurity admission controller.</li>
  </ul>
</div>
"@

                }
                "privilegedContainers" {
                    @"
<div class="recommendation-content">
  <h4>🛠️ Remove Privileged Containers</h4>
  <ul>
      <li><strong>Check:</strong> Inspect spec (<code>kubectl get pod <pod-name> -o yaml</code>).</li>
      <li><strong>Fix:</strong> Remove <code>privileged: true</code> from <code>securityContext</code>.</li>
      <li><strong>Capabilities:</strong> Use specific capabilities instead (<code>securityContext.capabilities.add</code>).</li>
      <li><strong>Audit:</strong> Block privileged pods with Open Policy Agent or PodSecurity admission controller.</li>
  </ul>
</div>
"@

                }
                "hostPidNet" {
                    @"
<div class="recommendation-content">
  <h4>🛠️ Disable Host PID/Network</h4>
  <ul>
      <li><strong>Inspect:</strong> Check pod spec (<code>kubectl get pod <pod-name> -o yaml</code>).</li>
      <li><strong>Fix:</strong> Set <code>hostPID: false</code> and <code>hostNetwork: false</code> in <code>spec</code>.</li>
      <li><strong>Use Case:</strong> Justify if required (e.g., monitoring tools), otherwise remove.</li>
      <li><strong>Security:</strong> Enforce via admission controllers to prevent host access.</li>
  </ul>
</div>
"@

                }
                "orphanedServiceAccounts" {
@"
<div class="recommendation-content">
  <h4>🛠️ Clean Up Orphaned ServiceAccounts</h4>
  <ul>
      <li><strong>Verify:</strong> Run <code>kubectl get sa -A</code> and check usage across pods, RoleBindings, and ClusterRoleBindings.</li>
      <li><strong>Delete:</strong> Remove unused SAs with <code>kubectl delete sa <name> -n <namespace></code>.</li>
      <li><strong>Audit:</strong> Confirm bindings and pods no longer reference the SA to avoid runtime issues.</li>
      <li><strong>Policy:</strong> Set up a process to review and clean up stale SAs periodically.</li>
  </ul>
</div>
"@

                }
                "orphanedRoles" {
@"
<div class="recommendation-content">
  <h4>🛠️ Remove Unused Roles and ClusterRoles</h4>
  <ul>
      <li><strong>List:</strong> Get all Roles and ClusterRoles using <code>kubectl get roles,clusterroles -A</code>.</li>
      <li><strong>Bindings:</strong> Confirm if they’re bound using <code>kubectl get rolebindings,clusterrolebindings -A</code>.</li>
      <li><strong>Prune:</strong> Delete unused roles with <code>kubectl delete role <name> -n <namespace></code> or <code>kubectl delete clusterrole <name></code>.</li>
      <li><strong>Review:</strong> Avoid clutter and reduce audit noise by cleaning up unbound roles regularly.</li>
  </ul>
</div>
"@

                }
                "eventSummary" {
                    @"
<div class="recommendation-content">
  <h4>🛠️ Address Cluster Events</h4>
  <ul>
      <li><strong>Correlate:</strong> Match events to resources (<code>kubectl describe <resource> <name></code>).</li>
      <li><strong>Root Cause:</strong> Investigate logs or metrics for warnings/errors.</li>
      <li><strong>Fix:</strong> Adjust resources (e.g., limits) or configs based on event type.</li>
      <li><strong>Monitor:</strong> Set up alerts for recurring critical events.</li>
  </ul>
</div>
"@

                }
                default {
                    @"
<div class="recommendation-content">
  <h4>🛠️ Generic Fix</h4>
  <ul>
      <li><strong>Inspect:</strong> Use <code>kubectl describe</code> on affected resources.</li>
      <li><strong>Logs:</strong> Check logs for clues (<code>kubectl logs</code>).</li>
      <li><strong>Config:</strong> Review and adjust YAML manifests.</li>
      <li><strong>Docs:</strong> Refer to Kubernetes documentation for specific guidance.</li>
  </ul>
</div>
"@

                }
            }
            $recommendation = @"
<div class="recommendation-card">
  <details style='margin-bottom: 10px;'>
      <summary style='color: #0071FF; font-weight: bold; font-size: 14px; padding: 10px; background: #E3F2FD; border-radius: 4px 4px 0 0;'>Recommendations</summary>
      $recommendationText
  </details>
</div>
<div style='height: 15px;'></div>
"@

        }

        $defaultText = if ($check.Id -eq "eventSummary") { "Show Event Findings" } else { "Show Findings" }
        $content = if ($noFindings) {
            "$pre`n"
        }
        else {
            "$pre`n" + (ConvertToCollapsible -Id $check.Id -defaultText $defaultText -content "$recommendation`n$html")
        }

        Set-Variable -Name ("collapsible" + $check.Id + "Html") -Value $content
    }

    $clusterSummaryText = $clusterSummaryRaw -join "`n"
    function Extract-Metric($label, $data) {
        if ($data -match "$label\s*:\s*([\d]+)") { [int]$matches[1] } else { "0" }
    }
    $clusterName = "Unknown"
    $k8sVersion = "Unknown"
    for ($i = 0; $i -lt $clusterSummaryRaw.Count; $i++) {
        $line = [string]$clusterSummaryRaw[$i] -replace "`r", "" -replace "`n", ""
        if ($line -match "Cluster Name\s*$") { $clusterName = [string]$clusterSummaryRaw[$i + 2] -replace "`r", "" -replace "`n", "" }
        if ($line -match "Kubernetes Version\s*$") { $k8sVersion = [string]$clusterSummaryRaw[$i + 2] -replace "`r", "" -replace "`n", "" }
    }
    $compatibilityCheck = if ($clusterSummaryText -match "⚠️\s+(Cluster is running an outdated version:[^\n]+)") { $matches[1].Trim(); $compatibilityClass = "warning" }
    elseif ($clusterSummaryText -match "✅ Cluster is up to date \((.*?)\)") { "✅ Cluster is up to date ($matches[1])"; $compatibilityClass = "healthy" }
    else { "Unknown"; $compatibilityClass = "unknown" }
    $totalNodes = Extract-Metric "🚀 Nodes" $clusterSummaryText
    $healthyNodes = Extract-Metric "🟩 Healthy" $clusterSummaryText
    $issueNodes = Extract-Metric "🟥 Issues" $clusterSummaryText
    $totalPods = Extract-Metric "📦 Pods" $clusterSummaryText
    $runningPods = Extract-Metric "🟩 Running" $clusterSummaryText
    $failedPods = Extract-Metric "🟥 Failed" $clusterSummaryText
    $totalRestarts = Extract-Metric "🔄 Restarts" $clusterSummaryText
    $warnings = Extract-Metric "🟨 Warnings" $clusterSummaryText
    $critical = Extract-Metric "🟥 Critical" $clusterSummaryText
    $pendingPods = Extract-Metric "⏳ Pending Pods" $clusterSummaryText
    $stuckPods = Extract-Metric "⚠️ Stuck Pods" $clusterSummaryText
    $jobFailures = Extract-Metric "📉 Job Failures" $clusterSummaryText
    $eventWarnings = Extract-Metric "⚠️ Warnings" $clusterSummaryText
    $eventErrors = Extract-Metric "❌ Errors" $clusterSummaryText
    $podAvg = if ($clusterSummaryText -match "📊 Pod Distribution: Avg: ([\d.]+)") { $matches[1] } else { "0" }
    $podMax = if ($clusterSummaryText -match "Max: ([\d.]+)") { $matches[1] } else { "0" }
    $podMin = if ($clusterSummaryText -match "Min: ([\d.]+)") { $matches[1] } else { "0" }
    $podTotalNodes = if ($clusterSummaryText -match "Total Nodes: ([\d]+)") { $matches[1] } else { "0" }
    $cpuUsage = if ($clusterSummaryText -match "🖥 CPU Usage:\s*([\d.]+)%") { [double]$matches[1] } else { 0 }
    $cpuStatus = if ($clusterSummaryText -match "🖥 CPU Usage:.*(🟩 Normal|🟡 Warning|🔴 Critical)") { $matches[1] } else { "Unknown" }
    $memUsage = if ($clusterSummaryText -match "💾 Memory Usage:\s*([\d.]+)%") { [double]$matches[1] } else { 0 }
    $memStatus = if ($clusterSummaryText -match "💾 Memory Usage:.*(🟩 Normal|🟡 Warning|🔴 Critical)") { $matches[1] } else { "Unknown" }

    $today = (Get-Date).ToUniversalTime().ToString("MMMM dd, yyyy HH:mm:ss 'UTC'")
    $year = (Get-Date).ToUniversalTime().ToString("yyyy")
    $thresholds = Get-KubeBuddyThresholds -Silent
    $excludedNamespaces = Get-ExcludedNamespaces -Silent
    $errorClass = if ($eventErrors -ge $thresholds.event_errors_critical) { "critical" } elseif ($eventErrors -ge $thresholds.event_errors_warning) { "warning" } else { "normal" }
    $warningClass = if ($eventWarnings -ge $thresholds.event_warnings_critical) { "critical" } elseif ($eventWarnings -ge $thresholds.event_warnings_warning) { "warning" } else { "normal" }
    $cpuClass = if ($cpuUsage -ge $thresholds.cpu_critical) { "critical" } elseif ($cpuUsage -ge $thresholds.cpu_warning) { "warning" } else { "normal" }
    $memClass = if ($memUsage -ge [double]$thresholds.mem_critical) { "critical" } elseif ($memUsage -ge [double]$thresholds.mem_warning) { "warning" } else { "normal" }

    if ($ExcludeNamespaces) {
        $excludedList = ($excludedNamespaces | ForEach-Object { "<span class='excluded-ns'>$_</span>" }) -join " • "
        $excludedNamespacesHtml = @"
<h2>Excluded Namespaces
<span class="tooltip"><span class="info-icon">i</span><span class="tooltip-text">These namespaces are excluded from analysis and reporting.</span></span>
</h2>
<p>$excludedList</p>
"@

    }
    else {
        $excludedNamespacesHtml = ""
    }

    $htmlTemplate = @"
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Kubernetes Cluster Report</title>
  <link rel="icon" href="https://raw.githubusercontent.com/KubeDeckio/KubeBuddy/refs/heads/main/docs/assets/images/favicon.ico" type="image/x-icon">
  <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<style>
  @import url('https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;700&display=swap');
  html { scroll-behavior: smooth; }
  body { font-family: 'Roboto', sans-serif; margin: 0; padding: 0; background: #eceff1; color: #37474f; }
  .header { background: linear-gradient(90deg, #005ad1, #0071FF); color: white; display: flex; justify-content: space-between; align-items: center; padding: 10px 24px; font-weight: bold; font-size: 24px; box-shadow: 0 4px 12px rgba(0,0,0,0.2); position: relative; top: auto; z-index: auto; }
  .header .nav-toggle { cursor: pointer; font-size: 28px; color: #fff; }
  .header .logo { height: 44px; margin-right: 12px; }
  .container { max-width: 1350px; margin: 20px auto; background: white; padding: 20px; border-radius: 12px; box-shadow: 0 6px 15px rgba(0, 0, 0, 0.1); }
  .compatibility { padding: 12px; border-radius: 8px; font-weight: bold; text-align: center; color: #ffffff; box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2); }
  .warning { background: #ffeb3b; } .healthy { background: #4CAF50; } .unknown { background: #9E9E9E; }
  .table-container { overflow-x: auto; width: 100%; max-width: 100%; }
  table { width: 100%; border-collapse: separate; border-spacing: 0; margin: 20px 0; font-size: 14px; text-align: left; background: #fff; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); border-left: 1px solid #e0e0e0; border-right: 1px solid #e0e0e0; }
  th { background-color: #0071FF; color: white; padding: 12px; font-weight: 500; }
  td { padding: 12px; border-bottom: 1px solid #e0e0e0; }
  tr:last-child td { border-bottom: none; }
  tr:hover td { background: #f5f5f5; transition: background 0.2s; }
  th:first-child { border-top-left-radius: 8px; }
  th:last-child { border-top-right-radius: 8px; }
  td:first-child { border-left: none; }
  td:last-child { border-right: none; }
  #backToTop { position: fixed; bottom: 20px; right: 20px; background: #0071FF; color: #fff; padding: 10px 15px; border-radius: 25px; text-decoration: none; font-size: 14px; font-weight: bold; box-shadow: 0 4px 12px rgba(0,0,0,0.3); display: none; transition: opacity 0.3s ease; }
  #backToTop:hover { background: #005ad1; }
  #printContainer { text-align: right; margin-bottom: 15px; }
  #printContainer button { background: #0071FF; color: white; padding: 10px 15px; border: none; cursor: pointer; font-size: 16px; border-radius: 8px; transition: background 0.3s; }
  #printContainer button:hover { background: #005ad1; }
  #savePdfBtn { background: #0071FF; color: white; padding: 8px 12px; font-size: 14px; font-weight: bold; border: none; cursor: pointer; border-radius: 8px; margin-top: 10px; transition: background 0.3s; }
  #savePdfBtn:hover { background: #005ad1; }
@media print {
    #savePdfBtn, #printContainer, .table-pagination, #menuFab {
        display: none !important; /* Add !important to override any inline styles */
    }
    details {
        display: block;
    }
    table {
        width: 100%;
        table-layout: fixed;
        border-collapse: collapse;
    }
    th, td {
        white-space: normal !important;
        overflow: visible !important;
        word-wrap: break-word;
        padding: 8px;
        border: 1px solid #ddd;
    }
    .table-container {
        overflow: visible !important;
        height: auto !important;
    }
}
  .excluded-ns { padding: 2px 6px; background-color: #eee; border-radius: 4px; margin-right: 4px; display: inline-block; }
  .nav-drawer { position: fixed; top: 0; left: -280px; width: 280px; height: 100%; background: linear-gradient(135deg, #f5f7fa, #ffffff); box-shadow: 4px 0 12px rgba(0,0,0,0.2); transition: left 0.3s ease-in-out; z-index: 2000; overflow-y: auto; }
  .nav-drawer.open { left: 0; }
  .nav-scrim { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0,0,0,0.4); z-index: 1999; display: none; }
  .nav-scrim.open { display: block; }
  .nav-content { padding: 20px; }
  .nav-header { padding: 20px; border-bottom: 1px solid #e0e0e0; display: flex; justify-content: space-between; align-items: center; background: #0071FF; color: #fff; }
  .nav-header h3 { margin: 0; font-size: 24px; font-weight: 700; }
  .nav-close { background: none; border: none; cursor: pointer; font-size: 28px; color: #fff; transition: color 0.3s; }
  .nav-close:hover { color: #BBDEFB; }
  .nav-items { list-style: none; padding: 0; margin: 0; }
  .nav-item { position: relative; }
  .nav-item a { display: flex; align-items: center; padding: 12px 20px; color: #37474f; text-decoration: none; font-size: 16px; font-weight: 400; transition: background-color 0.3s, color 0.3s; border-radius: 6px; }
  .nav-item a:hover { background: #E3F2FD; color: #005ad1; }
  .nav-item .material-icons { margin-right: 16px; font-size: 22px; color: #0071FF; }
  .nav-item details { margin: 5px 0; }
  .nav-item details summary { display: flex; align-items: center; padding: 12px 20px; color: #37474f; font-size: 16px; font-weight: 500; cursor: pointer; transition: background-color 0.3s, color 0.3s; border-radius: 6px; }
  .nav-item details summary:hover { background: #E3F2FD; color: #005ad1; }
  .nav-item details summary .material-icons { margin-right: 16px; font-size: 22px; color: #0071FF; }
  .nav-item details ul { padding-left: 48px; list-style: none; }
  .nav-item details ul li a { padding: 8px 20px; font-size: 14px; font-weight: 400; color: #455A64; border-radius: 6px; }
  .nav-item details ul li a:hover { background: #f0f4f8; color: #0071FF; }
  .ripple { position: absolute; border-radius: 50%; background: rgba(0,113,255,0.3); transform: scale(0); animation: ripple 0.6s linear; pointer-events: none; }
  @keyframes ripple { to { transform: scale(4); opacity: 0; } }
  @media (max-width: 800px) {
      .nav-drawer { width: 240px; left: -240px; }
      .nav-drawer.open { left: 0; }
  }
  details ul { margin-left: 1.5em; }
  .hero-metrics { display: flex; justify-content: space-around; margin-bottom: 20px; flex-wrap: wrap; }
  .metric-card { text-align: center; padding: 20px; border-radius: 10px; color: white; font-size: 20px; font-weight: bold; min-width: 150px; flex: 1; margin: 10px; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); }
  .normal { background-color: #388e3c; } .warning { background-color: #ffa000; } .critical { background-color: #B71C1C; } .default { background-color: #0071FF; }
  @media (max-width: 600px) { .hero-metrics { flex-direction: column; align-items: center; } .metric-card { width: 80%; } }
  .tooltip { display: inline-block; position: relative; cursor: pointer; margin-left: 8px; color: #0071FF; font-weight: bold; }
  .tooltip .tooltip-text { visibility: hidden; width: 260px; background-color: #0071FF; color: #fff; text-align: left; border-radius: 6px; padding: 8px; position: absolute; z-index: 10; bottom: 125%; left: 50%; margin-left: -130px; opacity: 0; transition: opacity 0.3s; font-size: 13px; }
  .tooltip:hover .tooltip-text { visibility: visible; opacity: 1; }
  .tooltip .tooltip-text::after { content: ""; position: absolute; top: 100%; left: 50%; margin-left: -6px; border-width: 6px; border-style: solid; border-color: #0071FF transparent transparent transparent; }
  .info-icon { font-size: 14px; border: 1px solid #0071FF; border-radius: 50%; padding: 0 5px; line-height: 1; display: inline-block; background-color: white; vertical-align: middle; position: relative; top: -2px; }
  .footer { background: linear-gradient(90deg, #263238, #37474f); color: white; text-align: center; padding: 20px; font-size: 14px; position: relative; }
  .footer a { color: #80cbc4; text-decoration: none; }
  .footer a:hover { text-decoration: underline; }
  .footer .logo { height: 30px; margin-bottom: 10px; }
  .recommendation-card { margin-bottom: 10px; }
  .recommendation-card details { background: #fff; border-radius: 8px; box-shadow: 0 2px 6px rgba(0,0,0,0.1); }
  .recommendation-card summary { padding: 12px; background: #E3F2FD; border-radius: 8px 8px 0 0; }
  .recommendation-card summary:hover { background: #BBDEFB; }
  .recommendation-content { padding: 15px; background: #f9f9f9; border: 1px solid #BBDEFB; border-top: none; border-radius: 0 0 8px 8px; color: #37474f; line-height: 1.6; }
  .recommendation-content h4 { margin: 0 0 10px 0; font-size: 16px; color: #0071FF; }
  .recommendation-content ul { padding-left: 20px; margin: 0; }
  .recommendation-content li { margin-bottom: 10px; }
  .recommendation-content code { background: #e0e0e0; padding: 2px 4px; border-radius: 4px; font-family: 'Courier New', Courier, monospace; }
.table-pagination {
  margin-top: 10px;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
}
.table-pagination select,
.table-pagination button {
  padding: 6px 12px;
  border-radius: 6px;
  border: 1px solid #ccc;
  background: #f7f7f7;
  cursor: pointer;
}
.table-pagination button[disabled] {
  opacity: 0.5;
  cursor: not-allowed;
}
.table-pagination .active {
  font-weight: bold;
  background: #0071FF;
  color: white;
}
  #menuFab {
  position: fixed;
  bottom: 20px;
  left: 20px;
  width: 52px;
  height: 52px;
  background-color: #0071FF;
  color: white;
  border: none;
  border-radius: 50%;
  font-size: 24px;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
  cursor: pointer;
  z-index: 2001;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background 0.3s ease;
}
#menuFab:hover {
  background-color: #005ad1;
}
</style>
</head>
<body>
<div class="nav-drawer" id="navDrawer">
  <div class="nav-header">
      <h3>Navigation</h3>
      <button class="nav-close" id="navClose">✖</button>
  </div>
  <div class="nav-content">
      <ul class="nav-items">
          <li class="nav-item"><a href="#summary"><span class="material-icons">dashboard</span> Cluster Summary</a></li>
          <li class="nav-item">
              <details>
                  <summary><span class="material-icons">computer</span> Nodes</summary>
                  <ul>
                      <li><a href="#nodecon">Node Conditions</a></li>
                      <li><a href="#noderesource">Node Resources</a></li>
                  </ul>
              </details>
          </li>
          <li class="nav-item">
            <details>
              <summary><span class="material-icons">folder</span> Namespaces</summary>
              <ul>
                <li><a href="#namespaces">Empty Namespaces</a></li>
                <li><a href="#resourceQuotas">ResourceQuotas</a></li>
                <li><a href="#namespaceLimitRanges">LimitRanges</a></li>
              </ul>
            </details>
          </li>
          <li class="nav-item">
            <details>
              <summary><span class="material-icons">build</span> Workloads</summary>
              <ul>
                <li><a href="#daemonsets">DaemonSets</a></li>
                <li><a href="#deploymentIssues">Deployment Issues</a></li>
                <li><a href="#statefulSetIssues">StatefulSet Issues</a></li>
                <li><a href="#HPA">Horizontal Pod Autoscalers</a></li>
                <li><a href="#missingResourceLimits">Missing Resource Limits</a></li>
                <li><a href="#PDB">PodDisruptionBudgets</a></li>
                <li><a href="#missingProbes">Missing Health Probes</a></li>
              </ul>
            </details>
          </li>
          <li class="nav-item">
              <details>
                  <summary><span class="material-icons">hexagon</span> Pods</summary>
                  <ul>
                      <li><a href="#podrestarts">Pods with High Restarts</a></li>
                      <li><a href="#podlong">Long Running Pods</a></li>
                      <li><a href="#podfail">Failed Pods</a></li>
                      <li><a href="#podpend">Pending Pods</a></li>
                      <li><a href="#crashloop">Pods in Crashloop</a></li>
                      <li><a href="#debugpods">Running Debug Pods</a></li>
                  </ul>
              </details>
          </li>
          <li class="nav-item">
              <details>
                  <summary><span class="material-icons">work</span> Jobs</summary>
                  <ul>
                      <li><a href="#stuckjobs">Stuck Jobs</a></li>
                      <li><a href="#failedjobs">Job Failures</a></li>
                  </ul>
              </details>
          </li>
          <li class="nav-item">
              <details>
                  <summary><span class="material-icons">network_check</span> Networking</summary>
                  <ul>
                      <li><a href="#servicenoendpoints">Services without Endpoints</a></li>
                      <li><a href="#publicServices">Public Services</a></li>
                      <li><a href="#ingressHealth">Ingress Health</a></li>
                  </ul>
              </details>
          </li>
          <li class="nav-item">
              <details>
                  <summary><span class="material-icons">storage</span> Storage</summary>
                  <ul>
                      <li><a href="#unmountedpv">Unmounted Persistent Volumes</a></li>
                  </ul>
              </details>
          </li>
          <li class="nav-item">
            <details>
              <summary><span class="material-icons">security</span> Security</summary>
              <ul>
                <!-- RBAC -->
                <li><a href="#rbacmisconfig">RBAC Misconfigurations</a></li>
                <li><a href="#rbacOverexposure">RBAC Overexposure</a></li>
                <li><a href="#orphanedRoles">Unused Roles</a></li>
                <li><a href="#orphanedServiceAccounts">Orphaned ServiceAccounts</a></li>
           
                <!-- Orphaned resources -->
                <li><a href="#orphanedconfigmaps">Orphaned ConfigMaps</a></li>
                <li><a href="#orphanedsecrets">Orphaned Secrets</a></li>
           
                <!-- Pod/container security -->
                <li><a href="#podsRoot">Pods Running as Root</a></li>
                <li><a href="#privilegedContainers">Privileged Containers</a></li>
                <li><a href="#hostPidNet">hostPID / hostNetwork</a></li>
              </ul>
            </details>
          </li>
          <li class="nav-item"><a href="#clusterwarnings"><span class="material-icons">warning</span> Kubernetes Events</a></li>
          $aksMenuItem
      </ul>
  </div>
</div>
<div class="nav-scrim" id="navScrim"></div>
<div id="top"></div>
<div class="header">
  <div style="display: flex; flex-direction: column;">
    <span>Kubernetes Cluster Report: $clusterName</span>
    <span style="font-size: 12px;">
      Powered by
      <img src="https://raw.githubusercontent.com/KubeDeckio/KubeBuddy/refs/heads/main/images/reportheader%20(2).png"
           alt="KubeBuddy Logo"
           style="height: 70px; vertical-align: middle;">
    </span>
  </div>
  <div style="text-align: right; font-size: 13px; line-height: 1.4;">
      <div>Generated on: <strong>$today</strong></div>
      <div>Created by <a href="https://kubedeck.io" target="_blank" style="color: #ffffff; text-decoration: underline;">🌐 KubeDeck.io</a></div>
      <div style="margin-top: 4px;" id="printContainer"><button id="savePdfBtn">📄 Save as PDF</button></div>
  </div>
</div>
<div class="container">
  <h1 id="summary">Cluster Summary</h1>
  <p><strong>Cluster Name:</strong> $clusterName</p>
  <p><strong>Kubernetes Version:</strong> $k8sVersion</p>
  <div class="compatibility $compatibilityClass"><strong>$compatibilityCheck</strong></div>
  <h2>Cluster Metrics Summary <span class="tooltip"><span class="info-icon">i</span><span class="tooltip-text">Summary of node and pod counts including warnings, restarts, and issues.</span></span></h2>
  <table>
      <tr><td>🚀 Nodes: $totalNodes</td><td>🟩 Healthy: $healthyNodes</td><td>🟥 Issues: $issueNodes</td></tr>
      <tr><td>📦 Pods: $totalPods</td><td>🟩 Running: $runningPods</td><td>🟥 Failed: $failedPods</td></tr>
      <tr><td>🔄 Restarts: $totalRestarts</td><td>🟨 Warnings: $warnings</td><td>🟥 Critical: $critical</td></tr>
      <tr><td>⏳ Pending Pods: $pendingPods</td><td>🟡 Waiting: $pendingPods</td><td></td></tr>
      <tr><td>⚠️ Stuck Pods: $stuckPods</td><td>❌ Stuck: $stuckPods</td><td></td></tr>
      <tr><td>📉 Job Failures: $jobFailures</td><td>🔴 Failed: $jobFailures</td><td></td></tr>
  </table>
  <h2>Pod Distribution <span class="tooltip"><span class="info-icon">i</span><span class="tooltip-text">Average, min, and max pods per node, and total node count.</span></span></h2>
  <table><tr><td>Avg: <strong>$podAvg</strong></td><td>Max: <strong>$podMax</strong></td><td>Min: <strong>$podMin</strong></td><td>Total Nodes: <strong>$podTotalNodes</strong></td></tr></table>
  <h2>Resource Usage <span class="tooltip"><span class="info-icon">i</span><span class="tooltip-text">Cluster-wide CPU and memory usage.</span></span></h2>
  <div class="hero-metrics">
      <div class="metric-card $cpuClass">🖥 CPU: <strong>$cpuUsage%</strong> <br><span>$cpuStatus</span></div>
      <div class="metric-card $memClass">💾 Memory: <strong>$memUsage%</strong> <br><span>$memStatus</span></div>
  </div>
  <h2>Cluster Events <span class="tooltip"><span class="info-icon">i</span><span class="tooltip-text">Recent warning and error events from the cluster.</span></span></h2>
  <div class="hero-metrics">
      <div class="metric-card $errorClass">❌ Errors: <strong>$eventErrors</strong></div>
      <div class="metric-card $warningClass">⚠️ Warnings: <strong>$eventWarnings</strong></div>
  </div>
  $excludedNamespacesHtml
</div>
<div class="container"><h1>Node Conditions & Resources</h1><h2 id="nodecon">Node Conditions <span class="tooltip"><span class="info-icon">i</span><span class="tooltip-text">Displays node readiness, taints, and schedulability.</span></span></h2><div class="table-container">$collapsibleNodeConditionsHtml</div><h2 id="noderesource">Node Resources <span class="tooltip"><span class="info-icon">i</span><span class="tooltip-text">Shows CPU and memory usage across nodes.</span></span></h2><div class="table-container">$collapsibleNodeResourcesHtml</div></div>
<div class="container"><h1 id="namespaces">Namespaces</h1><h2>Empty Namespaces <span class="tooltip"><span class="info-icon">i</span><span class="tooltip-text">Namespaces without any active workloads.</span></span></h2><div class="table-container">$collapsibleEmptyNamespaceHtml</div>
<h2 id="resourceQuotas">ResourceQuota Checks <span class="tooltip"><span class="info-icon">i</span><span class="tooltip-text">Detects namespaces lacking or missing quota definitions.</span></span></h2>
<div class="table-container">$collapsibleResourceQuotasHtml</div>
 
<h2 id="namespaceLimitRanges">LimitRange Checks <span class="tooltip"><span class="info-icon">i</span><span class="tooltip-text">Detects namespaces missing default resource limits.</span></span></h2>
<div class="table-container">$collapsibleNamespaceLimitRangesHtml</div>
</div>
<div class="container"><h1 id="workloads">Workloads</h1><h2 id="daemonsets">DaemonSets Not Fully Running <span class="tooltip"><span class="info-icon">i</span><span class="tooltip-text">Identifies DaemonSets with unavailable pods or rollout issues.</span></span></h2><div class="table-container">$collapsibleDaemonSetIssuesHtml</div>
 
<h2 id="deploymentIssues">Deployment Issues <span class="tooltip"><span class="info-icon">i</span><span class="tooltip-text">Identifies Deployments with unhealthy replicas or rollout problems.</span></span></h2>
<div class="table-container">$collapsibleDeploymentIssuesHtml</div>
 
<h2 id="statefulSetIssues">StatefulSet Issues <span class="tooltip"><span class="info-icon">i</span><span class="tooltip-text">Detects StatefulSets with unavailable pods or replica mismatches.</span></span></h2>
<div class="table-container">$collapsibleStatefulSetIssuesHtml</div>
 
<h2 id="HPA">Horizontal Pod Autoscalers <span class="tooltip"><span class="info-icon">i</span><span class="tooltip-text">Checks HPA presence and effectiveness.</span></span></h2>
  <div class="table-container">$collapsibleHPAHtml</div>
 
  <h2 id="missingResourceLimits">Missing Resource Requests & Limits <span class="tooltip"><span class="info-icon">i</span><span class="tooltip-text">Finds containers without memory/CPU requests or limits.</span></span></h2>
  <div class="table-container">$collapsibleMissingResourceLimitsHtml</div>
 
  <h2 id="PDB">PodDisruptionBudgets <span class="tooltip"><span class="info-icon">i</span><span class="tooltip-text">Detects missing or ineffective PDBs.</span></span></h2>
  <div class="table-container">$collapsiblePDBHtml</div>
 
  <h2 id="missingProbes">Missing Health Probes <span class="tooltip"><span class="info-icon">i</span><span class="tooltip-text">Reports containers missing readiness/liveness/startup probes.</span></span></h2>
  <div class="table-container">$collapsibleMissingProbesHtml</div>
</div>
<div class="container"><h1 id="pods">Pods</h1><h2 id="podrestarts">Pods with High Restarts <span class="tooltip"><span class="info-icon">i</span><span class="tooltip-text">Pods with restarts above the configured threshold.</span></span></h2><div class="table-container">$collapsiblePodsRestartHtml</div><h2 id="podlong">Long Running Pods <span class="tooltip"><span class="info-icon">i</span><span class="tooltip-text">Pods running beyond expected duration (e.g. stuck Jobs).</span></span></h2><div class="table-container">$collapsiblePodLongRunningHtml</div><h2 id="podfail">Failed Pods <span class="tooltip"><span class="info-icon">i</span><span class="tooltip-text">Pods that exited with a non-zero status.</span></span></h2><div class="table-container">$collapsiblePodFailHtml</div><h2 id="podpend">Pending Pods <span class="tooltip"><span class="info-icon">i</span><span class="tooltip-text">Pods pending scheduling or resource allocation.</span></span></h2><div class="table-container">$collapsiblePodPendingHtml</div><h2 id="crashloop">CrashLoopBackOff Pods <span class="tooltip"><span class="info-icon">i</span><span class="tooltip-text">Pods continuously crashing and restarting.</span></span></h2><div class="table-container">$collapsibleCrashloopHtml</div><h2 id="debugpods">Running Debug Pods <span class="tooltip"><span class="info-icon">i</span><span class="tooltip-text">Ephemeral containers or debug pods left running.</span></span></h2><div class="table-container">$collapsibleLeftoverdebugHtml</div></div>
<div class="container"><h1 id="jobs">Jobs</h1><h2 id="stuckjobs">Stuck Jobs <span class="tooltip"><span class="info-icon">i</span><span class="tooltip-text">Jobs that haven't progressed or completed as expected.</span></span></h2><div class="table-container">$collapsibleStuckJobsHtml</div><h2 id="failedjobs">Job Failures <span class="tooltip"><span class="info-icon">i</span><span class="tooltip-text">Jobs that exceeded retries or failed execution.</span></span></h2><div class="table-container">$collapsibleJobFailHtml</div></div>
<div class="container"><h1 id="networking">Networking</h1><h2 id="servicenoendpoints">Services without Endpoints <span class="tooltip"><span class="info-icon">i</span><span class="tooltip-text">Services that have no active pods backing them.</span></span></h2><div class="table-container">$collapsibleServicesWithoutEndpointsHtml</div><h2 id="publicServices">Publicly Accessible Services <span class="tooltip"><span class="info-icon">i</span><span class="tooltip-text">Services exposed via LoadBalancer or external IPs.</span></span></h2><div class="table-container">$collapsiblePublicServicesHtml</div>
<h2 id="ingressHealth">Ingress Configuration Issues <span class="tooltip"><span class="info-icon">i</span><span class="tooltip-text">Validates Ingress resources for misconfigurations or missing backend services.</span></span></h2>
<div class="table-container">$collapsibleIngressHealthHtml</div>
</div>
<div class="container"><h1 id="storage">Storage</h1><h2 id="unmountedpv">Unmounted Persistent Volumes <span class="tooltip"><span class="info-icon">i</span><span class="tooltip-text">Persistent volumes not currently mounted to any pod.</span></span></h2><div class="table-container">$collapsibleUnmountedpvHtml</div></div>
<div class="container"><h1 id="security">Security</h1>
 
<h2 id="rbacmisconfig">RBAC Misconfigurations <span class="tooltip"><span class="info-icon">i</span><span class="tooltip-text">RoleBindings or ClusterRoleBindings with missing subjects.</span></span></h2>
<div class="table-container">$collapsibleRbacmisconfigHtml</div>
 
<h2 id="rbacOverexposure">RBAC Overexposure <span class="tooltip"><span class="info-icon">i</span><span class="tooltip-text">Subjects with excessive or unnecessary privileges.</span></span></h2>
<div class="table-container">$collapsibleRbacOverexposureHtml</div>
 
<h2 id="orphanedRoles">Unused Roles & ClusterRoles <span class="tooltip"><span class="info-icon">i</span><span class="tooltip-text">Roles not referenced by any binding.</span></span></h2>
<div class="table-container">$collapsibleOrphanedRolesHtml</div>
 
<h2 id="orphanedServiceAccounts">Orphaned ServiceAccounts <span class="tooltip"><span class="info-icon">i</span><span class="tooltip-text">ServiceAccounts not used by any Pod or Binding.</span></span></h2>
<div class="table-container">$collapsibleOrphanedServiceAccountsHtml</div>
 
<h2 id="orphanedconfigmaps">Orphaned ConfigMaps <span class="tooltip"><span class="info-icon">i</span><span class="tooltip-text">ConfigMaps not referenced by any pod or controller.</span></span></h2>
<div class="table-container">$collapsibleOrphanedConfigMapsHtml</div>
 
<h2 id="orphanedsecrets">Orphaned Secrets <span class="tooltip"><span class="info-icon">i</span><span class="tooltip-text">Secrets that are unused or unmounted by workloads.</span></span></h2>
<div class="table-container">$collapsibleOrphanedSecretsHtml</div>
 
<h2 id="podsRoot">Pods Running as Root <span class="tooltip"><span class="info-icon">i</span><span class="tooltip-text">Containers running as UID 0.</span></span></h2>
<div class="table-container">$collapsiblePodsRootHtml</div>
 
<h2 id="privilegedContainers">Privileged Containers <span class="tooltip"><span class="info-icon">i</span><span class="tooltip-text">Containers running with privileged security context.</span></span></h2>
<div class="table-container">$collapsiblePrivilegedContainersHtml</div>
 
<h2 id="hostPidNet">hostPID / hostNetwork Enabled <span class="tooltip"><span class="info-icon">i</span><span class="tooltip-text">Containers sharing host PID or network namespaces.</span></span></h2>
<div class="table-container">$collapsibleHostPidNetHtml</div>
 
</div>
<div class="container"><h1 id="kubeevents">Kubernetes Warning Events</h1><h2 id="clusterwarnings">Recent Cluster Warnings <span class="tooltip"><span class="info-icon">i</span><span class="tooltip-text">Recent Warning and Error events from the cluster.</span></span></h2><div class="table-container">$collapsibleEventSummaryHtml</div></div>
$aksHealthCheck
<button id="menuFab" title="Open Menu">☰</button>
<footer class="footer">
  <img src="https://raw.githubusercontent.com/KubeDeckio/KubeBuddy/refs/heads/main/images/reportheader%20(2).png" alt="KubeBuddy Logo" class="logo">
  <p><strong>Report generated by KubeBuddy $version</strong> on $today</p>
  <p>© $year KubeBuddy | <a href="https://kubedeck.io" target="_blank">KubeDeck.io</a></p>
  <p><em>This report is a snapshot of the cluster state at the time of generation. It may not reflect real-time changes. Always verify configurations before making critical decisions.</em></p>
</footer>
<a href="#top" id="backToTop">Back to Top</a>
      <script>
      $jsContent
      </script>
</body>
</html>
"@


    $htmlTemplate | Set-Content $outputPath
}