WiFiAnalyzer.psm1

# Approved verb wrapper for export vars
function Get-WiFiAnalyzerExportVars {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$true)]$networks
    )
    # Call the original logic
    Update-WiFiAnalyzerExportVars -networks $networks
    return @{
        mac = $script:mac
        computerName = $script:computerName
        ipAddress = $script:ipAddress
        connectedSSID = $script:connectedSSID
        connectedBSSID = $script:connectedBSSID
        recommendedChannels = $script:recommended
        scanTime = $script:scanDateTime
    }
}
# Helper: Refresh all export variables for terminal usage
function Update-WiFiAnalyzerExportVars {
    param(
        [Parameter(Mandatory=$true)]$networks
    )
    $computerInfo = Get-ComputerInfoExtras
    $script:computerName = $computerInfo.ComputerName
    $script:ipAddress = $computerInfo.IPAddress
    $script:mac = $computerInfo.MACAddress
    $connected = Get-ConnectedSSID
    $script:connectedSSID = $connected.SSID
    $script:connectedBSSID = $connected.BSSID
    # Removed unused assignment to ifaceDetails
    # Ensure $networks is always an array
    if ($null -eq $networks) {
            # Error output removed
        $networks = @()
    } elseif ($networks -isnot [System.Collections.IEnumerable] -or $networks -is [string]) {
        $networks = @($networks)
    }
    $script:networks = $networks
    $script:recommended = Get-BestChannel $networks
    $script:scanDateTime = Get-Date -Format 'yyyy-MM-dd HH:mm:ss'
    $script:outputPath = "$PSScriptRoot\WiFiAnalyzerReport.html"
    # Debug output removed
}
# Analyze WiFi channel congestion and recommend best channels
function Test-WiFiChannelCongestion {
    $output = netsh wlan show networks mode=bssid | Out-String
    $channels = @()
    foreach ($line in $output -split "`r`n") {
        if ($line -match "Channel\s*:\s*(\d+)") {
            $channels += [int]$matches[1]
        }
    }
    if ($channels.Count -eq 0) {
        Write-Output "No WiFi channels detected."
        return
    }
    $grouped = $channels | Group-Object | Sort-Object Count -Descending
    $mostCongested = $grouped | Select-Object -First 3
    $leastCongested = $grouped | Where-Object { $_.Count -eq ($grouped | Select-Object -Last 1).Count }
    Write-Output "Most Congested Channels:" 
    foreach ($chan in $mostCongested) {
        Write-Output "Channel $($chan.Name): $($chan.Count) networks"
    }
    Write-Output "\nLeast Congested Channels:" 
    foreach ($chan in $leastCongested) {
        Write-Output "Channel $($chan.Name): $($chan.Count) networks"
    }
}
# Utility: Get-SecurityColor
function Get-SecurityColor {
    param(
        [string]$SecurityType
    )
    if ($SecurityType -match "WPA3") {
        return @('WPA3', [System.Drawing.Color]::Green)
    } elseif ($SecurityType -match "WPA2") {
        return @('WPA2', [System.Drawing.Color]::Blue)
    } elseif ($SecurityType -match "WPA") {
        return @('WPA', [System.Drawing.Color]::Orange)
    } elseif ($SecurityType -match "Open") {
        return @('Open', [System.Drawing.Color]::Red)
    } else {
        return @($SecurityType, [System.Drawing.Color]::Gray)
    }
}
# Utility: Get-SignalColor
function Get-SignalColor {
    param(
        [int]$SignalStrength
    )
    if ($SignalStrength -ge 80) {
        return @('Excellent', [System.Drawing.Color]::Green)
    } elseif ($SignalStrength -ge 60) {
        return @('Good', [System.Drawing.Color]::YellowGreen)
    } elseif ($SignalStrength -ge 40) {
        return @('Fair', [System.Drawing.Color]::Orange)
    } else {
        return @('Weak', [System.Drawing.Color]::Red)
    }
}
# Utility: ConvertTo-NotNull
function ConvertTo-NotNull {
    param(
        $InputObject,
        $DefaultValue
    )
    if ($null -ne $InputObject) {
        return $InputObject
    } else {
        return $DefaultValue
    }
}
function Get-ComputerInfoExtras {
    $os = (Get-CimInstance Win32_OperatingSystem).Caption
    $version = (Get-CimInstance Win32_OperatingSystem).Version
    $computerName = $env:COMPUTERNAME
    $ip = (Get-WmiObject Win32_NetworkAdapterConfiguration | Where-Object { $_.IPEnabled -eq $true } | Select-Object -ExpandProperty IPAddress)[0]
    $mac = (Get-WmiObject Win32_NetworkAdapterConfiguration | Where-Object { $_.IPEnabled -eq $true } | Select-Object -ExpandProperty MACAddress)[0]
    return @{ OS = $os; Version = $version; ComputerName = $computerName; IPAddress = $ip; MACAddress = $mac }
}
function Get-BestChannel {
    param([Parameter(Mandatory=$true)]$networks)
    # Ensure input is always an array
    if ($null -eq $networks) {
        return @{ '2.4GHz' = ''; '5GHz' = ''; CongestionData = @{} }
    }
    if ($networks -isnot [System.Collections.IEnumerable] -or $networks -is [string]) {
        $networks = @($networks)
    } elseif ($networks -is [System.Collections.IEnumerable]) {
        $networks = @($networks)
    }
    if (-not $networks -or $networks.Count -eq 0) {
        return @{ '2.4GHz' = ''; '5GHz' = ''; CongestionData = @{} }
    }
    $channels24 = $networks | Where-Object { $_.Channel -le 14 } | ForEach-Object { $_.Channel }
    $channels5 = $networks | Where-Object { $_.Channel -gt 14 } | ForEach-Object { $_.Channel }
    $best24 = if ($channels24) { ($channels24 | Group-Object | Sort-Object Count | Select-Object -First 1).Name } else { '' }
    $best5 = if ($channels5) { ($channels5 | Group-Object | Sort-Object Count | Select-Object -First 1).Name } else { '' }
    $congestion = Test-ChannelCongestion -networks $networks
    return @{ '2.4GHz' = $best24; '5GHz' = $best5; CongestionData = $congestion }
}

# Stub for missing manifest function
function Measure-NetworkSpeed {
    # Returns a dummy speed test result
    return @{ DownloadMbps = 100; UploadMbps = 50; PingMs = 10 }
}
if (-not ([AppDomain]::CurrentDomain.GetAssemblies() | Where-Object { $_.GetName().Name -eq 'System.Windows.Forms' })) {
    Add-Type -AssemblyName System.Windows.Forms
}
if (-not ([AppDomain]::CurrentDomain.GetAssemblies() | Where-Object { $_.GetName().Name -eq 'System.Drawing' })) {
    Add-Type -AssemblyName System.Drawing
}

function Get-ConnectedSSID {
    # Returns info about the currently connected WiFi network
    $output = netsh wlan show interfaces | Out-String
    $ssid = $null
    $bssid = $null
    foreach ($line in $output -split "`r`n") {
            # Debug output removed
        if ($line -match "^\s*SSID\s*:\s*(.+)$") {
            $ssid = $matches[1].Trim()
        }
        # Match 'AP BSSID' field for connected AP
        if ($line -match "^\s*AP BSSID\s*:\s*(.+)$") {
            $bssid = $matches[1].Trim()
        }
    }
    return @{ SSID = $ssid; BSSID = $bssid }
}
function Get-WiFiAdapterDetails {
    # Returns detailed info for all enabled network adapters
    $details = @{}
    $output = netsh wlan show interfaces | Out-String
    $current = @{}
    $ifaceName = $null
    foreach ($line in $output -split "`r`n") {
        if ($line -match "^\s*Name\s*:\s*(.+)$") { $ifaceName = $matches[1].Trim() }
        if ($line -match "^\s*Description\s*:\s*(.+)$") { $current.Description = $matches[1].Trim() }
        if ($line -match "^\s*GUID\s*:\s*(.+)$") { $current.GUID = $matches[1].Trim() }
        if ($line -match "^\s*Physical address\s*:\s*(.+)$") { $current.MAC = $matches[1].Trim() }
        if ($line -match "^\s*Interface type\s*:\s*(.+)$") { $current.InterfaceType = $matches[1].Trim() }
        if ($line -match "^\s*State\s*:\s*(.+)$") { $current.State = $matches[1].Trim() }
        if ($line -match "^\s*SSID\s*:\s*(.+)$") { $current.SSID = $matches[1].Trim() }
        if ($line -match "^\s*AP BSSID\s*:\s*(.+)$") { $current.BSSID = $matches[1].Trim() }
        if ($line -match "^\s*Band\s*:\s*(.+)$") { $current.Band = $matches[1].Trim() }
        if ($line -match "^\s*Channel\s*:\s*(.+)$") { $current.Channel = $matches[1].Trim() }
        if ($line -match "^\s*Network type\s*:\s*(.+)$") { $current.NetworkType = $matches[1].Trim() }
        if ($line -match "^\s*Radio type\s*:\s*(.+)$") { $current.RadioType = $matches[1].Trim() }
        if ($line -match "^\s*Authentication\s*:\s*(.+)$") { $current.Authentication = $matches[1].Trim() }
        if ($line -match "^\s*Cipher\s*:\s*(.+)$") { $current.Cipher = $matches[1].Trim() }
        if ($line -match "^\s*Connection mode\s*:\s*(.+)$") { $current.ConnectionMode = $matches[1].Trim() }
        if ($line -match "^\s*Receive rate \(Mbps\)\s*:\s*(.+)$") { $current.ReceiveRate = $matches[1].Trim() }
        if ($line -match "^\s*Transmit rate \(Mbps\)\s*:\s*(.+)$") { $current.TransmitRate = $matches[1].Trim() }
        if ($line -match "^\s*Signal\s*:\s*(.+)$") { $current.Signal = $matches[1].Trim() }
        if ($line -match "^\s*Profile\s*:\s*(.+)$") { $current.Profile = $matches[1].Trim() }
        if ($line -match "^\s*QoS MSCS Configured\s*:\s*(.+)$") { $current.QoSMSCSConfigured = $matches[1].Trim() }
        if ($line -match "^\s*QoS Map Configured\s*:\s*(.+)$") { $current.QoSMapConfigured = $matches[1].Trim() }
        if ($line -match "^\s*QoS Map Allowed by Policy\s*:\s*(.+)$") { $current.QoSMapAllowedByPolicy = $matches[1].Trim() }
    }
    if ($ifaceName) {
        $details[$ifaceName] = $current
    } else {
        $details["WiFi Adapter"] = @{ Error = "No WiFi interface found via netsh." }
    }
    return $details
}
function Get-MACAddress {
    # Try to get MAC address of the primary network adapter
    $adapters = Get-WmiObject Win32_NetworkAdapterConfiguration | Where-Object { $_.IPEnabled -eq $true }
    if ($adapters -and $adapters[0].MACAddress) {
        return $adapters[0].MACAddress
    } elseif ($adapters) {
        return $adapters[0].MACAddress
    } else {
        return "N/A"
    }
}
function Get-WiFiScan {
    $networks = @()
    $ssid = ""
    $security = ""
    $output = netsh wlan show networks mode=bssid | Out-String
    $lines = $output -split "`r`n"
    for ($i = 0; $i -lt $lines.Length; $i++) {
        $line = $lines[$i].Trim()
        if ($line -match "^SSID\s+\d+\s*:\s*(.+)$") {
            $ssid = $matches[1].Trim()
            $security = "Unknown"
        }
        if ($line -match "Authentication\s*:\s*(.+)$") {
            $security = $matches[1].Trim()
        }
        if ($line -match "^BSSID\s+\d+\s*:\s*(.+)$") {
            $bssid = $matches[1].Trim()
            $signal = $null
            $channel = $null
            $width = $null
            for ($j = 1; $j -le 8; $j++) {
                if ($i + $j -ge $lines.Length) { break }
                $nextLine = $lines[$i + $j].Trim()
                if ($nextLine -match "^Signal\s*:\s*(\d+)%") {
                    $signal = [int]$matches[1]
                } elseif ($nextLine -match "^Channel\s*:\s*(\d+)$") {
                    $channel = [int]$matches[1]
                } elseif ($nextLine -match "^Channel width\s*:\s*(.+)$") {
                    $width = $matches[1].Trim()
                }
            }
            if ($ssid -and $bssid -and $null -ne $signal -and $null -ne $channel) {
                $networks += [PSCustomObject]@{
                    SSID      = if ($ssid) { $ssid } else { "[Hidden Network]" }
                    BSSID     = $bssid
                    Signal    = $signal
                    Channel   = $channel
                    Security  = $security
                    Width     = if ($width) { $width } else { "Standard" }
                    Band      = if ($channel -gt 14) { "5 GHz" } else { "2.4 GHz" }
                }
            }
        }
    }
        return $networks
    }

function Export-WiFiAnalyzerHTMLReport {
    param(
        [string]$FilePath,
        [PSCustomObject[]]$networks,
        [string]$mac,
        [hashtable]$recommendedChannels,
        [string]$computerName,
        [string]$ipAddress,
        [hashtable]$userInfo,
        [string]$connectedSSID,
        [string]$connectedBSSID,
        [hashtable]$speedTest,
        [hashtable]$congestionData,
        [string]$scanTime = ""
    )
    $userRoomStr = ''
    if ($null -ne $userInfo -and $userInfo.RoomNumber) {
        $userRoomStr = [string]$userInfo.RoomNumber
    }

    # Defensive: ensure arrays/objects are not null
    if (-not $networks) { $networks = @() }
    if (-not $mac) { $mac = "" }
    if (-not $recommendedChannels) { $recommendedChannels = @{} }
    if (-not $computerName) { $computerName = "" }
    if (-not $ipAddress) { $ipAddress = "" }
    if (-not $userInfo) { $userInfo = @{} }
    if (-not $connectedSSID) { $connectedSSID = "" }
    if (-not $connectedBSSID) { $connectedBSSID = "" }
    if (-not $speedTest) { $speedTest = @{} }
    if (-not $congestionData) { $congestionData = @{} }

    $ifaceDetails = $null
    if ($PSBoundParameters.ContainsKey('ifaceDetails')) {
        $ifaceDetails = $ifaceDetails
    } else {
        $ifaceDetails = @{}
    }

    Write-Host "[DEBUG] Export-WiFiAnalyzerHTMLReport called with:" -ForegroundColor Yellow
    # Debug output removed
    $ifaceHtml = ""
    foreach ($key in $ifaceDetails.Keys) {
        $adapter = $ifaceDetails[$key]
        if ($adapter -is [hashtable]) {
            $fields = ""
            foreach ($field in $adapter.Keys) {
                $fields += '<strong>' + $field + ':</strong> ' + $adapter[$field] + '<br/>'
            }
            $ifaceHtml += "<div class='info-box'><h3>$key</h3><p style='font-size:0.98em;'>$fields</p></div>"
        } else {
            $ifaceHtml += "<div class='info-box'><h3>$key</h3><p>$($adapter)</p></div>"
        }
    }
    # Ensure system info fields are always populated
    $computerNameStr = if ($computerName) { [string]$computerName } elseif ($userInfo -and $userInfo.ComputerName) { [string]$userInfo.ComputerName } else { "N/A" }
    $ipAddressStr = if ($ipAddress) { [string]$ipAddress } elseif ($userInfo -and $userInfo.IPAddress) { [string]$userInfo.IPAddress } else { "N/A" }
    $macStr = if ($mac) { [string]$mac } elseif ($userInfo -and $userInfo.MACAddress) { [string]$userInfo.MACAddress } else { "N/A" }
    $connectedNetworkStr = if ($connectedNetwork) { [string]$connectedNetwork } elseif ($connectedSSID) { [string]$connectedSSID } elseif ($userInfo -and $userInfo.ConnectedNetwork) { [string]$userInfo.ConnectedNetwork } else { "N/A" }
    # ...existing code for ifaceHtml generation...
    # Ensure system info fields are always populated
    $computerNameStr = if ($computerName) { [string]$computerName } elseif ($userInfo -and $userInfo.ComputerName) { [string]$userInfo.ComputerName } else { "N/A" }
    $ipAddressStr = if ($ipAddress) { [string]$ipAddress } elseif ($userInfo -and $userInfo.IPAddress) { [string]$userInfo.IPAddress } else { "N/A" }
    $macStr = if ($mac) { [string]$mac } elseif ($userInfo -and $userInfo.MACAddress) { [string]$userInfo.MACAddress } else { "N/A" }
    # Add raw netsh wlan scan output
        try {
            $rawScan = netsh wlan show networks mode=bssid | Out-String
            # Annotate connected network in raw scan output
            if ($connectedSSID -and $connectedBSSID) {
                $scanLines = $rawScan -split "`r?`n"
                $curSSID = $null
                for ($i = 0; $i -lt $scanLines.Length; $i++) {
                    if ($scanLines[$i] -match "^SSID\\s+\\d+\\s*:\\s*(.+)$") {
                        $curSSID = $matches[1].Trim()
                    }
                    if ($scanLines[$i] -match "^BSSID\\s+\\d+\\s*:\\s*(.+)$") {
                        $curBSSID = $matches[1].Trim()
                        if ($curSSID -eq $connectedSSID -and $curBSSID -eq $connectedBSSID) {
                            $scanLines[$i] += " <--- Currently Connected"
                        }
                    }
                }
                $rawScan = $scanLines -join "`r`n"
            }
            $ifaceHtml += "<div class='info-box' style='white-space:pre-wrap;'><h3>Raw WiFi Scan Output</h3><pre style='font-size:0.95em;'>$rawScan</pre></div>"
        } catch {}
    # Add congestion analysis section
    $congestionHtml = ""
    if ($congestionData -and $congestionData.MostCongested -and $congestionData.LeastCongested) {
        $congestionHtml += "<div class='section'><h2>WiFi Channel Congestion Analysis</h2>"
        $congestionHtml += "<div class='info-box'><h3>Most Congested Channels</h3><ul>"
        foreach ($chan in $congestionData.MostCongested) {
            $congestionHtml += "<li>Channel $($chan.Name): $($chan.Count) networks</li>"
        }
        $congestionHtml += "</ul></div>"
        $congestionHtml += "<div class='info-box'><h3>Least Congested Channels</h3><ul>"
        foreach ($chan in $congestionData.LeastCongested) {
            $congestionHtml += "<li>Channel $($chan.Name): $($chan.Count) networks</li>"
        }
        $congestionHtml += "</ul></div></div>"
    }
    $networkRows = ""
    foreach ($network in ($networks | Sort-Object Signal -Descending)) {
        $signalClass = if ($network.Signal -ge 70) { "signal-strong" } elseif ($network.Signal -ge 40) { "signal-medium" } else { "signal-weak" }
        $securityClass = if ($network.Security -match "WPA3") { "security-wpa3" } elseif ($network.Security -match "WPA2") { "security-wpa2" } elseif ($network.Security -match "WPA") { "security-wpa" } elseif ($network.Security -match "Open") { "security-open" } else { "" }
        $bandBadge = if ($network.Band -eq "5 GHz") { "badge-5ghz" } else { "badge-24ghz" }
        $isConnected = $false
        if ($connectedSSID -and $connectedBSSID -and $network.SSID -eq $connectedSSID -and $network.BSSID -eq $connectedBSSID) {
            $isConnected = $true
        }
        $rowClass = if ($isConnected) { "connected-network" } else { "" }
        $networkRows += "<tr class='$rowClass'><td><strong>$($network.SSID)</strong></td><td style='font-family: Courier New, monospace; font-size: 0.9em;'>$($network.BSSID)</td><td class='$signalClass'>$($network.Signal)%</td><td><strong>$($network.Channel)</strong></td><td><span class='badge $bandBadge'>$($network.Band)</span></td><td class='$securityClass'>$($network.Security)</td></tr>"
    }
    $speedHtml = ""
    if ($speedTest -and $speedTest.Success) {
        $speedHtml = "<div class='section'><h2>Network Performance</h2><div class='info-box'><h3>Average Latency</h3><p>$($speedTest.AverageLatency) $($speedTest.Unit)</p></div></div>"
    }
    # Connected Network logic
    $connectedNetworkStr = if ($connectedSSID -and $connectedSSID -ne "") { [string]$connectedSSID } else { "Not Connected" }

    # Read HTML template from file
    $templatePath = Join-Path $PSScriptRoot 'WiFiAnalyzerTemplate.html'
    $html = Get-Content -Path $templatePath -Raw
    $scanTimeStr = [string]$scanTime
    $userNameStr = ''
    if ($null -ne $userInfo -and $userInfo.Name) {
        $userNameStr = [string]$userInfo.Name
    }
    $userEmailStr = ''
    if ($null -ne $userInfo -and $userInfo.Email) {
        $userEmailStr = [string]$userInfo.Email
    }
    $userLocationStr = ''
    if ($null -ne $userInfo -and $userInfo.Building) {
        $userLocationStr = [string]$userInfo.Building
    }
    $notesHtmlStr = [string]$notesHtml
    $ifaceHtmlStr = [string]$ifaceHtml
    # Ensure system info fields are always populated
    $computerNameStr = if ($computerName) { [string]$computerName } elseif ($userInfo -and $userInfo.ComputerName) { [string]$userInfo.ComputerName } else { "N/A" }
    $ipAddressStr = if ($ipAddress) { [string]$ipAddress } elseif ($userInfo -and $userInfo.IPAddress) { [string]$userInfo.IPAddress } else { "N/A" }
    $macStr = if ($mac) { [string]$mac } elseif ($userInfo -and $userInfo.MACAddress) { [string]$userInfo.MACAddress } else { "N/A" }
    $connectedNetworkStr = if ($connectedNetwork) { [string]$connectedNetwork } elseif ($connectedSSID) { [string]$connectedSSID } elseif ($userInfo -and $userInfo.ConnectedNetwork) { [string]$userInfo.ConnectedNetwork } else { "N/A" }
    $speedHtmlStr = [string]$speedHtml
    $recommended24Str = ''
    $recommended5Str = ''
    if ($null -ne $recommendedChannels) {
        if ($recommendedChannels.ContainsKey('2.4GHz')) {
            $recommended24Str = [string]$recommendedChannels['2.4GHz']
        }
        if ($recommendedChannels.ContainsKey('5GHz')) {
            $recommended5Str = [string]$recommendedChannels['5GHz']
        }
    }
    $networksCountStr = [string]$networks.Count
    $networkRowsStr = [string]$networkRows
    # Debug output removed
    $html = $html.Replace('__SCAN_DATE__', $scanTimeStr)
    $html = $html.Replace('__SCAN_TIME__', $scanTimeStr)
    $html = $html.Replace('__USER_NAME__', $userNameStr)
    $html = $html.Replace('__USER_EMAIL__', $userEmailStr)
    $html = $html.Replace('__USER_LOCATION__', $userLocationStr)
    $html = $html.Replace('__ROOM_NUMBER__', $userRoomStr)
    $html = $html.Replace('__NOTES_HTML__', $notesHtmlStr)
    $html = $html.Replace('__IFACE_HTML__', $ifaceHtmlStr)
    $html = $html.Replace('__CONGESTION_HTML__', $congestionHtml)
    $html = $html.Replace('__COMPUTER_NAME__', $computerNameStr)
    $html = $html.Replace('__IP_ADDRESS__', $ipAddressStr)
    $html = $html.Replace('__MAC_ADDRESS__', $macStr)
    $html = $html.Replace('__MAC__', $macStr)
    $html = $html.Replace('__CONNECTED_NETWORK__', $connectedNetworkStr)
    $html = $html.Replace('__SPEED_HTML__', $speedHtmlStr)
    $html = $html.Replace('__RECOMMENDED_24GHZ__', $recommended24Str)
    $html = $html.Replace('__RECOMMENDED_5GHZ__', $recommended5Str)
    $html = $html.Replace('__NETWORKS_COUNT__', $networksCountStr)
    $html = $html.Replace('__NETWORK_ROWS__', $networkRowsStr)
    $safeFilePath = Join-Path $PWD (Split-Path $FilePath -Leaf)
    $html | Out-File -FilePath $safeFilePath -Encoding UTF8
}

function Export-WiFiAnalyzerCSVReport {
    param(
        [string]$FilePath,
        $networks
    )
    
    if (-not $networks) { $networks = @() }
    # Add Connected column to CSV
    $connectedSSID = $global:connectedSSID
    $connectedBSSID = $global:connectedBSSID
    $csvRows = @()
    foreach ($network in $networks) {
        $isConnected = ($connectedSSID -and $connectedBSSID -and $network.SSID -eq $connectedSSID -and $network.BSSID -eq $connectedBSSID)
        $row = $network | Select-Object *
        if ($isConnected) {
            Add-Member -InputObject $row -MemberType NoteProperty -Name Connected -Value 'Yes'
        } else {
            Add-Member -InputObject $row -MemberType NoteProperty -Name Connected -Value ''
        }
        $csvRows += $row
    }
    $csvRows | Export-Csv -Path $FilePath -NoTypeInformation
}

<#
.SYNOPSIS
    Exports a WiFi analysis report to HTML or CSV format.
#>

function Export-WiFiAnalyzerFullReport {
        [CmdletBinding()]
        param(
            [Parameter(Mandatory = $false)]
            [PSCustomObject[]]$networks = @(),
            [ValidateSet('HTML', 'CSV')]
            [string]$OutputFormat = 'HTML',
            [Parameter(Mandatory = $false)]
            [string]$OutputPath,
            [Parameter(Mandatory = $false)]
            [switch]$SkipReportInfo,
            [object]$ifaceDetails = $null,
            [Parameter(Mandatory = $false)]
            [hashtable]$userInfo = $null,
            [Parameter(Mandatory = $false)]
            [string]$mac = "",
            [Parameter(Mandatory = $false)]
            [string]$computerName = "",
            [Parameter(Mandatory = $false)]
            [string]$ipAddress = "",
            [Parameter(Mandatory = $false)]
            $connected = $null,
            [Parameter(Mandatory = $false)]
            $speedTest = $null,
            [Parameter(Mandatory = $false)]
            $recommended = $null,
            [Parameter(Mandatory = $false)]
            [string]$scanTime = ""
        )
    
    # Removed unused variable assignments to fix warnings
    
        if (-not $SkipReportInfo -and $null -eq $userInfo) {
            Write-Host "Enter report information:" -ForegroundColor Cyan
            $name = Read-Host "Your Name"
            $email = Read-Host "Email (optional)"
            $location = Read-Host "Location (optional)"
            $roomNumber = Read-Host "Room Number (optional)"
            $userInfo = @{
                Name = $name
                Email = $email
                Location = $location
                RoomNumber = $roomNumber
            }
        } elseif ($null -eq $userInfo) {
            $userInfo = @{
                Name = "N/A"
                Email = "N/A"
                Location = "N/A"
                RoomNumber = "N/A"
            }
        }
    
    if (-not $OutputPath) {
        $timestamp = Get-Date -Format "yyyyMMdd_HHmmss"
        $extension = if ($OutputFormat -eq 'HTML') { 'html' } else { 'csv' }
        $desktopPath = [Environment]::GetFolderPath('Desktop')
        $OutputPath = Join-Path $desktopPath "WiFi_Report_$timestamp.$extension"
    }

    # Debug output removed

    # Ensure exportVars.connectedBSSID is set correctly
    if (-not $exportVars.connectedBSSID -or $exportVars.connectedBSSID -eq "") {
        if ($connected -and $connected.BSSID) {
            $exportVars.connectedBSSID = $connected.BSSID
        } else {
            $connInfo = Get-ConnectedSSID
            if ($connInfo -and $connInfo.BSSID) {
                $exportVars.connectedBSSID = $connInfo.BSSID
            }
        }
    }
    if ($OutputFormat -eq 'HTML') {
    # Debug output removed
        Export-WiFiAnalyzerHTMLReport -FilePath $OutputPath -networks $networks -mac $mac `
            -recommendedChannels $recommended -computerName $computerName `
            -ipAddress $ipAddress -userInfo $userInfo `
            -connectedSSID $exportVars.connectedSSID -connectedBSSID $exportVars.connectedBSSID `
            -speedTest $speedTest -congestionData $recommended.CongestionData -ifaceDetails $ifaceDetails -scanTime $scanTime
    } else {
        Export-WiFiAnalyzerCSVReport -FilePath $OutputPath -networks $networks
        # Output congestion analysis to command line
        if ($recommended.CongestionData -and $recommended.CongestionData.MostCongested -and $recommended.CongestionData.LeastCongested) {
            # Debug output removed
        }
        # Output raw netsh wlan scan to command line
        try {
            $rawScan = netsh wlan show networks mode=bssid | Out-String
            # Debug output removed
        } catch {}
    }
    # Debug output removed
}

# ===== COMMAND-LINE FUNCTION =====

<#
.SYNOPSIS
    Runs a complete WiFi analysis and exports results.
#>

function Start-WiFiAnalyzerAll {
    [CmdletBinding()]
    param (
        [string]$OutputFormat = "HTML",
        [string]$OutputPath = "",
        [switch]$SkipReportInfo
    )
    try {
        # If no output path specified, create one in user's Documents folder
        if ([string]::IsNullOrEmpty($OutputPath)) {
            $timestamp = Get-Date -Format "yyyyMMdd_HHmmss"
            $extension = if ($OutputFormat -eq 'HTML') { 'html' } else { 'csv' }
            $documentsPath = [Environment]::GetFolderPath('MyDocuments')
            $OutputPath = Join-Path $documentsPath "WiFi_Report_$timestamp.$extension"
        } else { 
            # Ensure the directory exists for the specified path
            $directory = Split-Path -Path $OutputPath -Parent 
            if (-not (Test-Path -Path $directory)) { 
                New-Item -Path $directory -ItemType Directory -Force | Out-Null 
                # Debug output removed
            }
        }
        
        $networks = Get-WiFiScan
        if ($null -eq $networks) {
            $networks = @()
        }
        $mac = Get-MACAddress
        $connected = Get-ConnectedSSID
        $info = Get-ComputerInfoExtras
        $computerName = $info.ComputerName
        $ipAddress = $info.IPAddress
        $ifaceDetails = $null
        if (Get-Command Get-WiFiAdapterDetails -ErrorAction SilentlyContinue) {
            $ifaceDetails = Get-WiFiAdapterDetails
        } else {
            $ifaceDetails = @{}
        }
        if (-not $networks) { $networks = @() }
        $recommendations = Get-BestChannel $networks
        $speedTest = Measure-NetworkSpeed

        Export-WiFiAnalyzerFullReport -networks $networks -OutputFormat $OutputFormat -OutputPath $OutputPath -SkipReportInfo:$SkipReportInfo -ifaceDetails $ifaceDetails -mac $mac -computerName $computerName -ipAddress $ipAddress -connected $connected -speedTest $speedTest -recommended $recommendations

    if ($SkipReportInfo) {
        # Debug output removed
        Write-Host "5 GHz Band : Channel $($recommendations.'5GHz')"
        Write-Host ""

        Write-Host "Signal Strength Legend:" -ForegroundColor Cyan
        Write-Host " Strong: 70-100% | Medium: 40-69% | Weak: 0-39%"
        Write-Host ""
        Write-Host "Security Type Legend:" -ForegroundColor Cyan
        Write-Host " WPA3: Most Secure | WPA2: Secure | WPA: Less Secure | Open: Not Secure"
        Write-Host ""
    }
    } catch {
        Write-Error "Start-WiFiAnalyzerAll failed: $_"
    }
}

# ===== GUIDED SETUP AND QUICK START FUNCTIONS =====

function Get-UserPreference {
    $preferencePath = Join-Path $env:APPDATA "WiFiAnalyzer_Preference.txt"
    if (Test-Path $preferencePath) {
        return Get-Content $preferencePath -Raw
    }
    return $null
}

function Set-UserPreference {
    param([string]$preference)
    $preferencePath = Join-Path $env:APPDATA "WiFiAnalyzer_Preference.txt"
    $preference | Out-File -FilePath $preferencePath -Force
}

function Show-StartupChoiceDialog {
    $form = New-Object System.Windows.Forms.Form
    $form.Text = "WiFi Analyzer - Welcome"
    $form.Size = New-Object System.Drawing.Size(500, 420)
    $form.StartPosition = "CenterScreen"
    $form.FormBorderStyle = "FixedDialog"
    $form.MaximizeBox = $false
    
        # Ensure the closing braces for the if/else blocks are present
        if (-not $OutputPath) {
            $timestamp = Get-Date -Format "yyyyMMdd_HHmmss"
            $extension = if ($OutputFormat -eq 'HTML') { 'html' } else { 'csv' }
            $OutputPath = Join-Path $PSScriptRoot "WiFi_Report_$timestamp.$extension"
        }
    $form.MinimizeBox = $false
    $form.BackColor = [System.Drawing.Color]::FromArgb(230, 248, 242) # Light accent
    
    # Title
    $title = New-Object System.Windows.Forms.Label
    $title.Location = New-Object System.Drawing.Point(20, 20)
    $title.Size = New-Object System.Drawing.Size(460, 40)
    $title.Text = "Welcome to WiFi Analyzer"
    $title.Font = New-Object System.Drawing.Font("Segoe UI", 18, [System.Drawing.FontStyle]::Bold)
    $title.ForeColor = [System.Drawing.Color]::FromArgb(12, 86, 64)
    $form.Controls.Add($title)
    
    # Description
    $description = New-Object System.Windows.Forms.Label
    $description.Location = New-Object System.Drawing.Point(20, 70)
    $description.Size = New-Object System.Drawing.Size(460, 40)
    $description.Text = "Choose how you'd like to start the WiFi Analyzer:"
    $description.Font = New-Object System.Drawing.Font("Segoe UI", 10)
    $form.Controls.Add($description)
    
    # Guided Setup Button
    $btnGuided = New-Object System.Windows.Forms.Button
    $btnGuided.Location = New-Object System.Drawing.Point(50, 130)
    $btnGuided.Size = New-Object System.Drawing.Size(400, 60)
    $btnGuided.Text = "Guided Setup - Learn the features (Recommended for first time)"
    $btnGuided.Font = New-Object System.Drawing.Font("Segoe UI", 10)
    $btnGuided.BackColor = [System.Drawing.Color]::FromArgb(12, 86, 64)
    $btnGuided.ForeColor = [System.Drawing.Color]::White
    $btnGuided.FlatStyle = [System.Windows.Forms.FlatStyle]::Flat
    $btnGuided.FlatAppearance.BorderSize = 0
    $form.Controls.Add($btnGuided)
    
    # Quick Start Button
    $btnQuick = New-Object System.Windows.Forms.Button
    $btnQuick.Location = New-Object System.Drawing.Point(50, 210)
    $btnQuick.Size = New-Object System.Drawing.Size(400, 60)
    $btnQuick.Text = "Quick Start - Jump right in"
    $btnQuick.Font = New-Object System.Drawing.Font("Segoe UI", 10)
    $btnQuick.BackColor = [System.Drawing.Color]::FromArgb(12, 86, 64)
    $btnQuick.ForeColor = [System.Drawing.Color]::White
    $btnQuick.FlatStyle = [System.Windows.Forms.FlatStyle]::Flat
    $btnQuick.FlatAppearance.BorderSize = 0
    $form.Controls.Add($btnQuick)
    
    # Remember choice checkbox
    $checkRemember = New-Object System.Windows.Forms.CheckBox
    $checkRemember.Location = New-Object System.Drawing.Point(50, 290)
    $checkRemember.Size = New-Object System.Drawing.Size(400, 30)
    $checkRemember.Text = "Remember my choice for next time"
    $checkRemember.Font = New-Object System.Drawing.Font("Segoe UI", 9)
    $form.Controls.Add($checkRemember)
    
    # Cancel Button
    $btnCancel = New-Object System.Windows.Forms.Button
    $btnCancel.Location = New-Object System.Drawing.Point(175, 330)
    $btnCancel.Size = New-Object System.Drawing.Size(150, 35)
    $btnCancel.Text = "Cancel"
    $btnCancel.Font = New-Object System.Drawing.Font("Segoe UI", 9)
    $btnCancel.BackColor = [System.Drawing.Color]::FromArgb(12, 86, 64)
    $btnCancel.ForeColor = [System.Drawing.Color]::White
    $form.Controls.Add($btnCancel)
    
    # Variable to store the choice - needs to be accessible in closures
    $choice = @{ Value = "Cancel" }
    
    $btnGuided.Add_Click({
        $choice.Value = "Guided"
        if ($checkRemember.Checked) {
            Set-UserPreference "Guided"
        }
        $form.Close()
    })
    
    $btnQuick.Add_Click({
        $choice.Value = "Quick"
        if ($checkRemember.Checked) {
            Set-UserPreference "Quick"
        }
        $form.Close()
    })
    
    $btnCancel.Add_Click({
        $choice.Value = "Cancel"
        $form.Close()
    })
    
    [void]$form.ShowDialog()
    
    return $choice.Value
}

function Start-GuidedSetup {
    try {
        $form = New-Object System.Windows.Forms.Form
        $form.Text = "WiFi Analyzer - Guided Setup"
        $form.Size = New-Object System.Drawing.Size(700, 550)
        $form.StartPosition = "CenterScreen"
    $form.BackColor = [System.Drawing.Color]::FromArgb(230, 248, 242)
        
        $title = New-Object System.Windows.Forms.Label
        $title.Location = New-Object System.Drawing.Point(30, 20)
        $title.Size = New-Object System.Drawing.Size(640, 40)
        $title.Text = "WiFi Analyzer Features Tour"
        $title.Font = New-Object System.Drawing.Font("Segoe UI", 18, [System.Drawing.FontStyle]::Bold)
    $title.ForeColor = [System.Drawing.Color]::FromArgb(12, 86, 64)
        $form.Controls.Add($title)
        
        $infoText = New-Object System.Windows.Forms.RichTextBox
        $infoText.Location = New-Object System.Drawing.Point(30, 70)
        $infoText.Size = New-Object System.Drawing.Size(640, 380)
        $infoText.ReadOnly = $true
        $infoText.Font = New-Object System.Drawing.Font("Segoe UI", 10)
        $infoText.BorderStyle = [System.Windows.Forms.BorderStyle]::None
    $infoText.BackColor = [System.Drawing.Color]::FromArgb(245, 249, 250)
        
        $infoText.Text = @"
Welcome to WiFi Analyzer!

This tool helps you analyze WiFi networks in your area. Here's what you can do:

SCAN NETWORKS
   Click the 'Scan Networks' button to detect all nearby WiFi networks.
   You'll see signal strength, channels, security types, and more.

CHANNEL ANALYSIS
   The tool automatically recommends the best channels for both 2.4 GHz
   and 5 GHz bands based on network congestion.

SYSTEM INFORMATION
   View your computer name, IP address, MAC address, and current
   connection status.

EXPORT REPORTS
   Generate professional HTML or CSV reports with all scan data.
   Perfect for documentation and troubleshooting.

COLOR-CODED RESULTS
   - Green: Strong signal or secure network
   - Orange: Medium signal or moderate security
   - Red: Weak signal or insecure network
   - Blue: WPA2 security (recommended standard)

Ready to start? Click Continue to open the WiFi Analyzer!
"@

        
        $form.Controls.Add($infoText)
        
        $btnContinue = New-Object System.Windows.Forms.Button
        $btnContinue.Location = New-Object System.Drawing.Point(250, 465)
        $btnContinue.Size = New-Object System.Drawing.Size(120, 40)
        $btnContinue.Text = "Continue"
        $btnContinue.Font = New-Object System.Drawing.Font("Segoe UI", 10, [System.Drawing.FontStyle]::Bold)
    $btnContinue.BackColor = [System.Drawing.Color]::FromArgb(12, 86, 64)
    $btnContinue.ForeColor = [System.Drawing.Color]::White
        $btnContinue.FlatStyle = [System.Windows.Forms.FlatStyle]::Flat
        $btnContinue.FlatAppearance.BorderSize = 0
        $btnContinue.DialogResult = [System.Windows.Forms.DialogResult]::OK
        $form.Controls.Add($btnContinue)
        
        $btnCancel = New-Object System.Windows.Forms.Button
        $btnCancel.Location = New-Object System.Drawing.Point(390, 465)
        $btnCancel.Size = New-Object System.Drawing.Size(120, 40)
        $btnCancel.Text = "Cancel"
        $btnCancel.Font = New-Object System.Drawing.Font("Segoe UI", 10)
        $btnCancel.DialogResult = [System.Windows.Forms.DialogResult]::Cancel
        $form.Controls.Add($btnCancel)
        
        $result = $form.ShowDialog()
        return ($result -eq [System.Windows.Forms.DialogResult]::OK)
    } catch {
        [System.Windows.Forms.MessageBox]::Show(
            "Guided Setup failed: $($_.Exception.Message)",
            "Guided Setup Error",
            [System.Windows.Forms.MessageBoxButtons]::OK,
            [System.Windows.Forms.MessageBoxIcon]::Error
        )
        return $false
    }
}

function Start-QuickStart {
    try {
        $result = [System.Windows.Forms.MessageBox]::Show(
            "WiFi Analyzer is ready to scan!`n`nClick OK to continue to the main interface.",
            "Quick Start",
            [System.Windows.Forms.MessageBoxButtons]::OKCancel,
            [System.Windows.Forms.MessageBoxIcon]::Information
        )
        return ($result -eq [System.Windows.Forms.DialogResult]::OK)
    } catch {
        [System.Windows.Forms.MessageBox]::Show(
            "Quick Start failed: $($_.Exception.Message)",
            "Quick Start Error",
            [System.Windows.Forms.MessageBoxButtons]::OK,
            [System.Windows.Forms.MessageBoxIcon]::Error
        )
        return $false
    }
}

function Get-MainWiFiAnalyzerForm {
    # Create main form
    $form = New-Object System.Windows.Forms.Form
    $form.Text = "WiFi Network Analyzer"
    $form.Size = New-Object System.Drawing.Size(1100, 700)
    $form.StartPosition = "CenterScreen"
    $form.BackColor = [System.Drawing.Color]::FromArgb(230, 248, 242)
    
    # Title Header Panel
    $headerPanel = New-Object System.Windows.Forms.Panel
    $headerPanel.Location = New-Object System.Drawing.Point(0, 0)
    $headerPanel.Size = New-Object System.Drawing.Size(1100, 80)
    $headerPanel.BackColor = [System.Drawing.Color]::FromArgb(12, 86, 64)
    $form.Controls.Add($headerPanel)
    
    # Title Label
    $titleLabel = New-Object System.Windows.Forms.Label
    $titleLabel.Location = New-Object System.Drawing.Point(20, 15)
    $titleLabel.Size = New-Object System.Drawing.Size(500, 50)
    $titleLabel.Text = "WiFi Network Analyzer"
    $titleLabel.Font = New-Object System.Drawing.Font("Segoe UI", 24, [System.Drawing.FontStyle]::Bold)
    $titleLabel.ForeColor = [System.Drawing.Color]::White
    $headerPanel.Controls.Add($titleLabel)
    
    # Scan Button
    $scanButton = New-Object System.Windows.Forms.Button
    $scanButton.Location = New-Object System.Drawing.Point(40, 100)
    $scanButton.Size = New-Object System.Drawing.Size(200, 50)
    $scanButton.Text = "Scan Networks"
    $scanButton.Font = New-Object System.Drawing.Font("Segoe UI", 12, [System.Drawing.FontStyle]::Bold)
    $scanButton.BackColor = [System.Drawing.Color]::FromArgb(12, 86, 64)
    $scanButton.ForeColor = [System.Drawing.Color]::White
    $scanButton.FlatStyle = [System.Windows.Forms.FlatStyle]::Flat
    $scanButton.FlatAppearance.BorderSize = 0
    $form.Controls.Add($scanButton)
    
               # Annotate connected AP in outputBox
               if ($script:connectedSSID -and $script:connectedBSSID -and $network.SSID -eq $script:connectedSSID -and $network.BSSID -eq $script:connectedBSSID) {
                   $outputBox.SelectionColor = [System.Drawing.Color]::FromArgb(255, 248, 176)
                   $outputBox.SelectionFont = New-Object System.Drawing.Font("Segoe UI", 11, [System.Drawing.FontStyle]::Bold)
                   $outputBox.AppendText(" <--- Currently Connected")
                   $outputBox.SelectionColor = [System.Drawing.Color]::Black
                   $outputBox.SelectionFont = New-Object System.Drawing.Font("Segoe UI", 11, [System.Drawing.FontStyle]::Bold)
               }
               $outputBox.AppendText("`r`n")
    # Export Button
    $exportButton = New-Object System.Windows.Forms.Button
    $exportButton.Location = New-Object System.Drawing.Point(260, 100)
    $exportButton.Size = New-Object System.Drawing.Size(200, 50)
    $exportButton.Text = "Export Report"
    $exportButton.Font = New-Object System.Drawing.Font("Segoe UI", 12, [System.Drawing.FontStyle]::Bold)
    $exportButton.BackColor = $scanButton.BackColor
    $exportButton.ForeColor = [System.Drawing.Color]::White
    $exportButton.FlatStyle = [System.Windows.Forms.FlatStyle]::Flat
    $exportButton.FlatAppearance.BorderSize = 0
    $exportButton.Enabled = $false
    $form.Controls.Add($exportButton)
    
    # Output Box
    $outputBox = New-Object System.Windows.Forms.RichTextBox
    $outputBox.Location = New-Object System.Drawing.Point(40, 170)
    $outputBox.Size = New-Object System.Drawing.Size(1010, 480)
    $outputBox.Font = New-Object System.Drawing.Font("Segoe UI", 10)
    $outputBox.ReadOnly = $true
    $outputBox.BackColor = [System.Drawing.Color]::FromArgb(245, 249, 250)
    $outputBox.BorderStyle = [System.Windows.Forms.BorderStyle]::FixedSingle
    $form.Controls.Add($outputBox)
    
    # Script-level variables to store scan results
    $script:networks = @()
    $script:mac = ""
        if ($dataGridView) {
            for ($i = 0; $i -lt $dataGridView.Rows.Count; $i++) {
                $row = $dataGridView.Rows[$i]
                $ssid = $row.Cells[0].Value
                $bssid = $row.Cells[1].Value
                if ($script:connectedSSID -and $script:connectedBSSID -and $ssid -eq $script:connectedSSID -and $bssid -eq $script:connectedBSSID) {
                    $row.DefaultCellStyle.BackColor = [System.Drawing.Color]::FromArgb(255, 248, 176)
                    $row.DefaultCellStyle.ForeColor = [System.Drawing.Color]::FromArgb(0, 0, 0)
                    $row.DefaultCellStyle.Font = New-Object System.Drawing.Font($dataGridView.Font, [System.Drawing.FontStyle]::Bold)
                }
            }
        }
    $script:recommended = @{}
    $script:computerName = ""
    $script:ipAddress = ""
    $script:connectedSSID = ""
    $script:connectedBSSID = ""
    $script:speedTest = $null
    $script:congestionData = @{}
    
    # Scan button event handler
    $scanButton.Add_Click({
        try {
            $outputBox.Clear()
            $outputBox.SelectionFont = New-Object System.Drawing.Font("Segoe UI", 12, [System.Drawing.FontStyle]::Bold)
            $outputBox.SelectionColor = [System.Drawing.Color]::FromArgb(12, 86, 64)
            $outputBox.AppendText("Scanning WiFi Networks...`r`n`r`n")
            $outputBox.Refresh()
            
            # Get WiFi networks
            $script:networks = Get-WiFiScan
            $computerInfo = Get-ComputerInfoExtras
            $script:computerName = $computerInfo.ComputerName
            $script:ipAddress = $computerInfo.IPAddress
            $script:mac = $computerInfo.MACAddress
            $connected = Get-ConnectedSSID
            $script:connectedSSID = $connected.SSID
            $script:connectedBSSID = $connected.BSSID
            # Record scan date and time
            $script:scanDateTime = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
            
            # Get recommendations
            $script:recommended = Get-BestChannel -networks $script:networks
            $script:congestionData = $script:recommended.CongestionData
            
            # Test speed (quick test)
            $script:speedTest = Measure-NetworkSpeed
            
            $outputBox.Clear()
            
            # Computer Information Section
            $outputBox.SelectionFont = New-Object System.Drawing.Font("Segoe UI", 14, [System.Drawing.FontStyle]::Bold)
            $outputBox.SelectionColor = [System.Drawing.Color]::FromArgb(12, 86, 64)
            $outputBox.AppendText("System Information`r`n")
            $outputBox.SelectionColor = [System.Drawing.Color]::Black
            $outputBox.AppendText("--------------------------------------------------`r`n")
            
            $outputBox.SelectionFont = New-Object System.Drawing.Font("Segoe UI", 10)
            $outputBox.AppendText("Computer Name: $($script:computerName)`r`n")
            $outputBox.AppendText("IP Address : $($script:ipAddress)`r`n")
            $outputBox.AppendText("MAC Address : $($script:mac)`r`n")
            
            if ($script:connectedSSID) {
                $outputBox.AppendText("Connected To : $($script:connectedSSID)`r`n")
                $outputBox.AppendText("BSSID : $($script:connectedBSSID)`r`n")
            } else {
                $outputBox.AppendText("Connected To : Not connected to WiFi`r`n")
            }
            
            if ($script:speedTest -and $script:speedTest.Success) {
                $outputBox.AppendText("Avg Latency : $($script:speedTest.AverageLatency) $($script:speedTest.Unit)`r`n")
            }
            
            $outputBox.AppendText("`r`n")

            # WiFi Interface Details Section
            $ifaceDetails = ConvertTo-NotNull (Get-WiFiAdapterDetails) @{}
            $outputBox.SelectionFont = New-Object System.Drawing.Font("Segoe UI", 14, [System.Drawing.FontStyle]::Bold)
            $outputBox.SelectionColor = [System.Drawing.Color]::FromArgb(12, 86, 64)
            $outputBox.AppendText("WiFi Interface Details`r`n")
            $outputBox.SelectionColor = [System.Drawing.Color]::Black
            $outputBox.AppendText("--------------------------------------------------`r`n")
            $outputBox.SelectionFont = New-Object System.Drawing.Font("Segoe UI", 10)
            foreach ($key in $ifaceDetails.Keys) {
                $adapter = $ifaceDetails[$key]
                if ($adapter -is [hashtable]) {
                    $outputBox.AppendText($key + "`r`n")
                    foreach ($field in $adapter.Keys) {
                        $outputBox.AppendText(" " + $field + ": " + $adapter[$field] + "`r`n")
                    }
                } else {
                    $outputBox.AppendText($key + " : " + $adapter + "`r`n")
                }
            }
            $outputBox.AppendText("`r`n")
            
            # Networks Found Section
            $outputBox.SelectionFont = New-Object System.Drawing.Font("Segoe UI", 14, [System.Drawing.FontStyle]::Bold)
            $outputBox.SelectionColor = [System.Drawing.Color]::FromArgb(12, 86, 64)
            $outputBox.AppendText("Detected Networks ($($script:networks.Count) Found)`r`n")
            $outputBox.SelectionColor = [System.Drawing.Color]::Black
            $outputBox.AppendText("--------------------------------------------------`r`n`r`n")
            
            if ($script:networks.Count -eq 0) {
                $outputBox.SelectionColor = [System.Drawing.Color]::Red
                $outputBox.SelectionFont = New-Object System.Drawing.Font("Segoe UI", 10, [System.Drawing.FontStyle]::Bold)
                $outputBox.AppendText("No networks found. Make sure WiFi is enabled.`r`n")
            }
            else {
                $sortedNetworks = $script:networks | Sort-Object Signal -Descending
                
                foreach ($network in $sortedNetworks) {
                    $signalText, $signalColor = Get-SignalColor $network.Signal
                    $securityText, $securityColor = Get-SecurityColor $network.Security
                    
                    # SSID in bold
                    $outputBox.SelectionFont = New-Object System.Drawing.Font("Segoe UI", 11, [System.Drawing.FontStyle]::Bold)
                    $outputBox.SelectionColor = [System.Drawing.Color]::Black
                    $outputBox.AppendText("$($network.SSID)`r`n")
                    
                    # Network details
                    $outputBox.SelectionFont = New-Object System.Drawing.Font("Segoe UI", 9)
                    $outputBox.AppendText(" BSSID: $($network.BSSID) | Channel: $($network.Channel) ($($network.Band))`r`n")
                    
                    # Signal strength with color
                    $outputBox.AppendText(" Signal: ")
                    $outputBox.SelectionStart = $outputBox.TextLength
                    $outputBox.SelectionLength = 0
                    $outputBox.SelectionColor = $signalColor
                    $outputBox.SelectionFont = New-Object System.Drawing.Font("Segoe UI", 9, [System.Drawing.FontStyle]::Bold)
                    $outputBox.AppendText("$($network.Signal)% ($signalText)")
                    
                    # Security with color
                    $outputBox.SelectionColor = [System.Drawing.Color]::Black
                    $outputBox.SelectionFont = New-Object System.Drawing.Font("Segoe UI", 9)
                    $outputBox.AppendText(" | Security: ")
                    $outputBox.SelectionStart = $outputBox.TextLength
                    $outputBox.SelectionLength = 0
                    $outputBox.SelectionColor = $securityColor
                    $outputBox.SelectionFont = New-Object System.Drawing.Font("Segoe UI", 9, [System.Drawing.FontStyle]::Bold)
                    $outputBox.AppendText($securityText)
                    
                    $outputBox.SelectionColor = [System.Drawing.Color]::Black
                    $outputBox.SelectionFont = New-Object System.Drawing.Font("Segoe UI", 9)
                    $outputBox.AppendText("`r`n`r`n")
                }
            }
            
            # Channel Recommendations
            $outputBox.SelectionFont = New-Object System.Drawing.Font("Segoe UI", 14, [System.Drawing.FontStyle]::Bold)
            $outputBox.SelectionColor = [System.Drawing.Color]::FromArgb(12, 86, 64)
            $outputBox.AppendText("Channel Recommendations`r`n")
            $outputBox.SelectionColor = [System.Drawing.Color]::Black
            $outputBox.AppendText("--------------------------------------------------`r`n")
            
            $outputBox.SelectionFont = New-Object System.Drawing.Font("Segoe UI", 10)
            $outputBox.AppendText("2.4 GHz Band: Channel $($script:recommended.'2.4GHz')`r`n")
            $outputBox.AppendText("5 GHz Band : Channel $($script:recommended.'5GHz')`r`n`r`n")
            
            # Legends
            $outputBox.SelectionFont = New-Object System.Drawing.Font("Segoe UI", 11, [System.Drawing.FontStyle]::Bold)
            $outputBox.AppendText("Signal Strength Legend:`r`n")
            $outputBox.SelectionFont = New-Object System.Drawing.Font("Segoe UI", 10)
            
            $outputBox.SelectionStart = $outputBox.TextLength
            $outputBox.SelectionLength = 0
            $outputBox.SelectionColor = [System.Drawing.Color]::Green
            $outputBox.AppendText("Strong: 70-100% ")

            $outputBox.SelectionStart = $outputBox.TextLength
            $outputBox.SelectionLength = 0
            $outputBox.SelectionColor = [System.Drawing.Color]::Black
            $outputBox.AppendText("| ")

            $outputBox.SelectionStart = $outputBox.TextLength
            $outputBox.SelectionLength = 0
            $outputBox.SelectionColor = [System.Drawing.Color]::Orange
            $outputBox.AppendText("Medium: 40-69% ")

            $outputBox.SelectionStart = $outputBox.TextLength
            $outputBox.SelectionLength = 0
            $outputBox.SelectionColor = [System.Drawing.Color]::Black
            $outputBox.AppendText("| ")

            $outputBox.SelectionStart = $outputBox.TextLength
            $outputBox.SelectionLength = 0
            $outputBox.SelectionColor = [System.Drawing.Color]::Red
            $outputBox.AppendText("Weak: 0-39%")

            $outputBox.SelectionStart = $outputBox.TextLength
            $outputBox.SelectionLength = 0
            $outputBox.SelectionColor = [System.Drawing.Color]::Black
            $outputBox.AppendText("`r`n`r`n")
            
            # Security legend
            $outputBox.SelectionFont = New-Object System.Drawing.Font("Segoe UI", 11, [System.Drawing.FontStyle]::Bold)
            $outputBox.AppendText("Security Type Legend:`r`n")
            $outputBox.SelectionFont = New-Object System.Drawing.Font("Segoe UI", 10)
            
            $outputBox.SelectionStart = $outputBox.TextLength
            $outputBox.SelectionLength = 0
            $outputBox.SelectionColor = [System.Drawing.Color]::Green
            $outputBox.AppendText("WPA3: Most Secure ")

            $outputBox.SelectionStart = $outputBox.TextLength
            $outputBox.SelectionLength = 0
            $outputBox.SelectionColor = [System.Drawing.Color]::Blue
            $outputBox.AppendText("WPA2: Secure ")

            $outputBox.SelectionStart = $outputBox.TextLength
            $outputBox.SelectionLength = 0
            $outputBox.SelectionColor = [System.Drawing.Color]::Orange
            $outputBox.AppendText("WPA: Less Secure ")

            $outputBox.SelectionStart = $outputBox.TextLength
            $outputBox.SelectionLength = 0
            $outputBox.SelectionColor = [System.Drawing.Color]::Red
            $outputBox.AppendText("Open: Not Secure")

            $outputBox.SelectionColor = [System.Drawing.Color]::Black
            
            # Enable export button
            $exportButton.Enabled = $script:networks.Count -gt 0
        } catch {
            [System.Windows.Forms.MessageBox]::Show("Error during scan: $($_.Exception.Message)", "Error")
        }
    })
    # End of scan button event handler

    # Export button event handler
    $exportButton.Add_Click({
                    Write-Host "[DEBUG] Exporting report with system info:" -ForegroundColor Yellow
                    Write-Host " Computer Name: $($script:computerName)" -ForegroundColor Gray
                    Write-Host " IP Address: $($script:ipAddress)" -ForegroundColor Gray
                    Write-Host " MAC Address: $($script:mac)" -ForegroundColor Gray
                    Write-Host " Connected SSID: $($script:connectedSSID)" -ForegroundColor Gray
                    Write-Host " Connected BSSID: $($script:connectedBSSID)" -ForegroundColor Gray
        try {
            if ($script:networks.Count -gt 0) {
                $userInfo = Show-WiFiReportInfoForm
                if ($userInfo) {
                    # Refresh all system info and recommendations before export
                    $computerInfo = Get-ComputerInfoExtras
                    $script:computerName = $computerInfo.ComputerName
                    $script:ipAddress = $computerInfo.IPAddress
                    $script:mac = $computerInfo.MACAddress
                    $connected = Get-ConnectedSSID
                    $script:connectedSSID = $connected.SSID
                    $script:connectedBSSID = $connected.BSSID
                    $ifaceDetails = ConvertTo-NotNull (Get-WiFiAdapterDetails) @{}
                    $script:recommended = Get-BestChannel $script:networks
                    $outputPath = "$PSScriptRoot\WiFiAnalyzerReport.html"
                    Write-Host "[DEBUG][GUI] Exporting report with refreshed values:" -ForegroundColor Yellow
                    Write-Host " Computer Name: $($script:computerName)" -ForegroundColor Gray
                    Write-Host " IP Address: $($script:ipAddress)" -ForegroundColor Gray
                    Write-Host " MAC Address: $($script:mac)" -ForegroundColor Gray
                    Write-Host " Connected SSID: $($script:connectedSSID)" -ForegroundColor Gray
                    Write-Host " Connected BSSID: $($script:connectedBSSID)" -ForegroundColor Gray
                    Write-Host " Recommended Channels: $($script:recommended | Out-String)" -ForegroundColor Gray
                    Write-Host " Scan Time: $script:scanDateTime" -ForegroundColor Gray
                    Export-WiFiAnalyzerFullReport -networks $script:networks -OutputFormat 'HTML' -OutputPath $outputPath -ifaceDetails $ifaceDetails -userInfo $userInfo -mac $script:mac -computerName $script:computerName -ipAddress $script:ipAddress -connected $connected -recommended $script:recommended -scanTime $script:scanDateTime -SkipReportInfo
                    $result = [System.Windows.Forms.MessageBox]::Show("Report exported successfully. Would you like to quit?", "Export Complete", [System.Windows.Forms.MessageBoxButtons]::YesNo, [System.Windows.Forms.MessageBoxIcon]::Question)
                    if ($result -eq [System.Windows.Forms.DialogResult]::Yes) {
                        $form.Close()
                    }
                }
            } else {
                [System.Windows.Forms.MessageBox]::Show("Nothing to export. Please run a scan first.", "Export Error")
            }
        } catch {
            [System.Windows.Forms.MessageBox]::Show("Export error: $($_.Exception.Message)", "Error")
        }
    })
    # End of export button event handler

    # Show the form
    [void]$form.ShowDialog()
}

<#
.SYNOPSIS
    Launches the WiFi Analyzer GUI directly without any startup screens.
#>

function Start-WiFiAnalyzerDirect {
    [CmdletBinding()]
    param()
    
    Write-Host "Launching WiFi Analyzer..." -ForegroundColor Cyan
    Get-MainWiFiAnalyzerForm
    Write-Host "WiFi Analyzer closed." -ForegroundColor Cyan
}

<#
.SYNOPSIS
    Starts the WiFi Analyzer application with startup options.
#>

function Start-WiFiAnalyzer {
    [CmdletBinding()]
    param(
        [switch]$QuickStart,
        [switch]$SkipPreflightCheck
    )
    
    Write-Host "WiFi Analyzer Starting..." -ForegroundColor Cyan
    
    # Check command line parameters first
    if ($QuickStart -or $SkipPreflightCheck) {
        Write-Host "Quick start mode selected" -ForegroundColor Yellow
    Get-MainWiFiAnalyzerForm
        return
    }
    
    # Check saved preference
    $savedPreference = Get-UserPreference
    if ($savedPreference) {
        Write-Host "Found saved preference: $savedPreference" -ForegroundColor Yellow
        
        switch ($savedPreference.Trim()) {
            "Guided" {
                Write-Host "Running guided setup..." -ForegroundColor Green
                if (Start-GuidedSetup) {
                    Write-Host "Guided setup complete, launching main form..." -ForegroundColor Green
                    Get-MainWiFiAnalyzerForm
                } else {
                    Write-Host "Guided setup cancelled by user" -ForegroundColor Red
                }
                return
            }
            "Quick" {
                Write-Host "Running quick start..." -ForegroundColor Green
                if (Start-QuickStart) {
                    Write-Host "Quick start complete, launching main form..." -ForegroundColor Green
                    Get-MainWiFiAnalyzerForm
                } else {
                    Write-Host "Quick start cancelled by user" -ForegroundColor Red
                }
                return
            }
        }
    }
    
    # No preference saved, show choice dialog
    Write-Host "No saved preference found, showing choice dialog..." -ForegroundColor Yellow
    
    $choice = Show-StartupChoiceDialog
    
    Write-Host "User selected: $choice" -ForegroundColor Yellow
    
    switch ($choice) {
        "Guided" {
            Write-Host "Starting Guided Setup..." -ForegroundColor Green
            if (Start-GuidedSetup) {
                Write-Host "Guided setup completed, showing main form..." -ForegroundColor Green
                Get-MainWiFiAnalyzerForm
            } else {
                Write-Host "Guided setup was cancelled" -ForegroundColor Red
            }
        }
        "Quick" {
            Write-Host "Starting Quick Start..." -ForegroundColor Green
            if (Start-QuickStart) {
                Write-Host "Quick start completed, showing main form..." -ForegroundColor Green
                Get-MainWiFiAnalyzerForm
            } else {
                Write-Host "Quick start was cancelled" -ForegroundColor Red
            }
        }
        "Cancel" {
            Write-Host "User cancelled startup dialog" -ForegroundColor Red
        }
        default {
            Write-Host "Unexpected choice: '$choice', launching main form anyway..." -ForegroundColor Yellow
            Get-MainWiFiAnalyzerForm
        }
    }
    
    Write-Host "WiFi Analyzer session ended." -ForegroundColor Cyan
}

# Aliases
Set-Alias -Name Show-WiFiAnalyzerGUI -Value Get-MainWiFiAnalyzerForm
Set-Alias -Name WiFi-Analyzer -Value Start-WiFiAnalyzer
Set-Alias -Name Scan-WiFi -Value Get-WiFiScan
# Note: Do NOT alias Get-WiFiNetworks to Get-WiFiScan - that would shadow
# the existing code..
function Show-WiFiReportInfoForm {
    $form = New-Object System.Windows.Forms.Form
    $form.Text = "Report Info"
    $form.Size = New-Object System.Drawing.Size(400, 360)
    $form.StartPosition = "CenterScreen"

    $labels = @("Your Name:", "ID Number:", "Email Address:", "Telephone Number:", "Building:", "Room Number:")
    $textboxes = @()

    for ($i = 0; $i -lt $labels.Count; $i++) {
        $label = New-Object System.Windows.Forms.Label
        $label.Text = $labels[$i]
        $label.Location = New-Object System.Drawing.Point -ArgumentList 20, (30 + ($i * 40))
        $label.Size = New-Object System.Drawing.Size(120, 20)
        $form.Controls.Add($label)

        $textbox = New-Object System.Windows.Forms.TextBox
        $textbox.Location = New-Object System.Drawing.Point -ArgumentList 150, (30 + ($i * 40))
        $textbox.Size = New-Object System.Drawing.Size(220, 20)
        $form.Controls.Add($textbox)
        $textboxes += $textbox
    }

    $okButton = New-Object System.Windows.Forms.Button
    $okButton.Text = "OK"
    $okButton.Location = New-Object System.Drawing.Point -ArgumentList 150, 270
    $okButton.Size = New-Object System.Drawing.Size(100, 30)
    $okButton.DialogResult = [System.Windows.Forms.DialogResult]::OK
    $form.AcceptButton = $okButton
    $form.Controls.Add($okButton)

    $result = $form.ShowDialog()
    if ($result -eq [System.Windows.Forms.DialogResult]::OK) {
        return @{
            Name = $textboxes[0].Text
            ID = $textboxes[1].Text
            Email = $textboxes[2].Text
            Phone = $textboxes[3].Text
            Building = $textboxes[4].Text
            RoomNumber = $textboxes[5].Text
        }
    } else {
        return $null
    }
}

function Test-ChannelCongestion {
    param(
        [Parameter(Mandatory = $true)]
        [PSCustomObject[]]$networks
    )
    if (-not $networks -or $networks.Count -eq 0) {
        Write-Error "Test-ChannelCongestion: 'networks' parameter must be a non-empty array."
        return $null
    }
    $channelAnalysis = @{} 

    $networks24GHz = $networks | Where-Object { [int]$_.Channel -le 14 }
    $networks5GHz = $networks | Where-Object { [int]$_.Channel -gt 14 }

    foreach ($network in $networks24GHz) {
        $channel = [int]$network.Channel
        $signal = [int]$network.Signal

        $startChannel = [Math]::Max(1, $channel - 4)
        $endChannel = [Math]::Min(14, $channel + 4)

        for ($i = $startChannel; $i -le $endChannel; $i++) {
            $distance = [Math]::Abs($i - $channel)
            $impact = $signal * (1 - ($distance / 5))

            if ($channelAnalysis.ContainsKey($i)) {
                $channelAnalysis[$i] += $impact
            } else {
                $channelAnalysis[$i] = $impact
            }
        }
    }

    foreach ($network in $networks5GHz) {
        $channel = [int]$network.Channel
        $signal = [int]$network.Signal

        if ($channelAnalysis.ContainsKey($channel)) {
            $channelAnalysis[$channel] += $signal
        } else {
            $channelAnalysis[$channel] = $signal
        }
    }

    return $channelAnalysis
}

# Exported wrapper for manifest compliance
function Export-WiFiReport {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true)]
        [PSCustomObject[]]$networks,
        [ValidateSet('HTML', 'CSV')]
        [string]$OutputFormat = 'HTML',
        [Parameter(Mandatory = $false)]
        [string]$OutputPath,
        [Parameter(Mandatory = $false)]
        [object]$ifaceDetails = $null,
        [Parameter(Mandatory = $false)]
        [hashtable]$userInfo = $null,
        [Parameter(Mandatory = $false)]
        [switch]$SkipReportInfo
    )
    Export-WiFiAnalyzerFullReport -networks $networks -OutputFormat $OutputFormat -OutputPath $OutputPath -ifaceDetails $ifaceDetails -userInfo $userInfo -SkipReportInfo $SkipReportInfo
}