# --- [Command-Line Parameter Support] ---
param (
    [Parameter()]
    [string]$COMPORT = "6"  # Default COM port for testing
)

### --- [Step 1] Elevate: Ensure script is running with Administrator privileges ---

if (-not ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator)) {
    $argsLine = $MyInvocation.UnboundArguments -join " "
    Start-Process -FilePath "powershell.exe" -ArgumentList "-ExecutionPolicy Bypass -File `"$PSCommandPath`" $argsLine" -Verb RunAs
    exit
}

# Force working directory to script location after elevation
Set-Location -Path $PSScriptRoot

# Validate COM port parameter
if (-not $COMPORT) {
    Write-Host "Missing COM port argument. Please call this script with a COM port, e.g. powershell.exe -File script.ps1 6"
    exit 1
}

Write-Host "Selected COM Port: $COMPORT" -ForegroundColor Yellow

### --- [Step 2] Initialize variables, log directory paths, and file names ---

$FTDI_Prog_CmdExePath = "C:\Program Files (x86)\FTDI\FT_Prog\FT_Prog-CmdLine.exe"

# Customized serial numbers and Bus Prefix
# Expected FTDI serial number
$FTDI_TargetSerial = "FT90HOHLA"
# Expected FTDI VID/PID
$FTDI_BusPrefix = "VID_0403+PID_6001"

$MFGTool_IF91X_Download_Path = (Get-Location).Path
# Write-Output "MFGTool Path: $MFGTool_IF91X_Download_Path"

# Obtain system time (format YYYYMMDDHHMMSS)
$timestamp = Get-Date -Format "yyyyMMddHHmmss"
# Write-Output "Timestamp: $timestamp"

# Read the content of UserScanInput.txt (two levels above the script)
# Write-Output "Folder File Content: $content"
$userInputPath = Join-Path -Path $PSScriptRoot -ChildPath "..\\..\\UserScanInput.txt"
if (-not (Test-Path $userInputPath)) {
    Write-Host "UserScanInput.txt not found: $userInputPath" -ForegroundColor Red
    exit 3
}
$content = Get-Content -Path $userInputPath -Raw

# Start recording the entire script output to a log file
# Get the path of the parent directory two levels up from the current working directory
$MiddlelogDir = Split-Path -Path $MFGTool_IF91X_Download_Path -Parent

# Combine the paths to get the final Logs directory path
$MiddlelogDir = Join-Path -Path $MiddlelogDir -ChildPath "Logs"
$logDir = Join-Path -Path $MiddlelogDir -ChildPath $content

# Replace the $(system time) part of the file name with $content
$Output_Txtfile = "${content}_wlanfw_download_process-if91x_results_${timestamp}.txt"
$StandardOutput_Txtfile = "wlanfw_download_process-if91x_results.txt"

# Check if the $content folder exists, and create it if not
$folderPath = Join-Path -Path $MiddlelogDir -ChildPath $content
if (-Not (Test-Path -Path $folderPath)) {
    Write-Host "Creating folder: $folderPath"
    New-Item -Path $folderPath -ItemType Directory | Out-Null
}

# Full path to the output file
$OutputFilePath = Join-Path -Path $logDir -ChildPath $Output_Txtfile

Write-Host "Resolved OutputFilePath: $OutputFilePath"
Write-Host "Resolved LogDir: $logDir"

# Check if the script has permissions to write to the file
if (-not (Test-Path -Path $OutputFilePath)) {
    try {
        New-Item -ItemType File -Path $OutputFilePath -Force | Out-Null
    } catch {
        Write-Host "Failed to create log file: $OutputFilePath" -ForegroundColor Red
        exit 4
    }
}

# Define a function to encapsulate Write-Log and log it.
function Write-Log {
    param (
        [string]$message
    )
    Write-Host $Message
    $Message | Out-File -FilePath $OutputFilePath -Append
}

Write-Log .

# Veda IF91x: Execute to download the Wi-Fi firmware
Write-Log "Veda IF91x : Execute to download the Wi-Fi firmware"

# Function to check error and stop execution with timeout
function Check-Error {
    param([int]$ExitCode, [string]$Step = "")
    if ($ExitCode -ne 0) {
        Write-Log "Error encountered at step: $Step (ExitCode=$ExitCode)"
        Write-Log "Transmit failure ..."
        Copy-Item -Path $OutputFilePath -Destination (Join-Path $logDir $StandardOutput_Txtfile) -Force
        exit $ExitCode
    }
}

Write-Log "Please be patient for about 10 seconds for program WLAN firmware..."
Write-Log "...******************************..."
Write-Log "...*** DO NOT PRESS ANY KEY ! ***..."
Write-Log "...******************************..."
Write-Log ".."

### --- [Step 3] Scan and match FTDI device by serial and BusPrefix to obtain InstanceId ---

# --- Auto-correct COM port for WL (prefer COMX) ---
# Resolve FTDI COM port by VID/PID + Serial via Win32_SerialPort
function Resolve-WLComPort {
    param(
        [string]$VidPidPrefix,  # e.g., "VID_0403+PID_6001"
        [string]$TargetSerial   # e.g., "FT8EBIIHA"
    )
    try {
        # Convert "VID_0403+PID_6001" to a regex that can match both & and +, for example, "VID_0403.*PID_6001"
        $vidpidRegex = ($VidPidPrefix -replace '\+','.*')
        $rx = [regex]"$vidpidRegex.*$([regex]::Escape($TargetSerial))"

        # --- Plan A: Win32_SerialPort (Capture COMx directly) ---
        $ports = Get-CimInstance Win32_SerialPort -ErrorAction Stop | Where-Object {
            $_.PNPDeviceID -and $rx.IsMatch($_.PNPDeviceID)
        }
        if ($ports) {
            $best = $ports | Sort-Object {
                if ($_.DeviceID -match '^COM(\d+)$') { [int]$Matches[1] } else { 9999 }
            } | Select-Object -First 1
            if ($best -and $best.DeviceID -match '^COM(\d+)$') { return $Matches[1] }
        }

        # --- Plan B: Win32_PnPEntity 
        #             (Sometimes SerialPort cannot be captured, but there is Name: "USB Serial Port (COMX)") ---
        $pnps = Get-CimInstance Win32_PnPEntity -ErrorAction Stop | Where-Object {
            $_.PNPDeviceID -and $rx.IsMatch($_.PNPDeviceID) -and ($_.Name -match '\(COM\d+\)')
        }
        if ($pnps) {
            foreach ($n in $pnps) {
                if ($n.Name -match '\(COM(\d+)\)') { return $Matches[1] }
            }
        }

        # --- Plan C: Registry read FTDI PortName directly ---
        # HKLM:\SYSTEM\CurrentControlSet\Enum\FTDIBUS\VID_0403+PID_6001+FT8FNBQUA\0000\Device Parameters\PortName
        $regPath = "HKLM:\SYSTEM\CurrentControlSet\Enum\FTDIBUS\{0}+{1}\0000\Device Parameters" -f $VidPidPrefix, $TargetSerial
        if (Test-Path $regPath) {
            $port = (Get-ItemProperty -Path $regPath -Name 'PortName' -ErrorAction Stop).PortName
            if ($port -match '^COM(\d+)$') { return $Matches[1] }
        }
    } 
    catch {
        Write-Log ("Resolve-BTComPort error: {0}" -f $_.Exception.Message)
    }
    return $null
}

# Prefer VID/PID/SN detection; fallback: keep user COM if valid -> else Expected
$ExpectedWLCom = "6"

Write-Log ("Auto-detecting WL COM by VID/PID/SN (Prefix={0}, SN={1})..." -f $FTDI_BusPrefix, $FTDI_TargetSerial)
$detected = Resolve-WLComPort -VidPidPrefix $FTDI_BusPrefix -TargetSerial $FTDI_TargetSerial

    if ($detected) {
        $COMPORT = $detected
    Write-Log ("Detected FTDI via VID/PID/SN -> COM{0}" -f $COMPORT)
}
else {
    # Check if the COM given by the user exists; if it exists, respect it and do not overwrite it
    $userOk = $false
    try {
        $userOk = (Get-CimInstance Win32_SerialPort | Where-Object { $_.DeviceID -eq ("COM{0}" -f $COMPORT) }) -ne $null
    } catch { $userOk = $false }

    if ($userOk) {
        Write-Log ("VID/PID detection failed; keeping user-specified COM{0}" -f $COMPORT)
    } else {
        Write-Log ("VID/PID detection failed; falling back to COM{0}" -f $ExpectedWLCom)
        $COMPORT = $ExpectedWLCom
    }
}
Write-Log ("WL will use COM{0}" -f $COMPORT)

### --- [Step 3-1] Scan and match FTDI device by serial and BusPrefix to obtain InstanceId ---
# Get Hardware VIDs/PIDs of connected FTDI bus via devcon (optional verification)
$devcon = "devcon64.exe"
if (-not (Get-Command $devcon -ErrorAction SilentlyContinue)) {
    Write-Log "WARNING: devcon64.exe not found in PATH. FTDI verification skipped."
} else {
    $devconOutput = & $devcon hwids *FTDI* 2>$null
    $instanceId = $devconOutput | Where-Object { $_ -like "*$FTDI_BusPrefix+$FTDI_TargetSerial\0000" } | Select-Object -First 1

    if (-not $instanceId) {
        Write-Log ("FTDI device not found by devcon (Serial={0}, Prefix={1})." -f $FTDI_TargetSerial, $FTDI_BusPrefix)
        # We do not hard-fail here since COM was already resolved; uncomment to enforce:
        # Copy-Item -Path $OutputFilePath -Destination (Join-Path $logDir $StandardOutput_Txtfile) -Force
        # exit 5
    } else {
        Write-Log "Found FTDI device Instance ID:"
        Write-Log ("    {0}" -f $instanceId)
    }
}

### --- [Step 4] Modify Registry to set LatencyTimer = 1 and restart FTDI device ---

# Setting the Registry Path and Latency Values to 1
$registryPath = "Registry::HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\FTDIBUS\$FTDI_BusPrefix+$FTDI_TargetSerial\0000\Device Parameters"
Set-ItemProperty -Path $registryPath -Name "LatencyTimer" -Value 1

# Display confirmation
$lat = Get-ItemProperty -Path $registryPath | Select-Object -ExpandProperty LatencyTimer
Write-Host "LatencyTimer already set：$lat ms" -ForegroundColor Cyan

Write-Host "Restarting the FTDI device bus..."
Start-Process -FilePath "devcon64.exe" -ArgumentList "restart `"$instanceId`"" -Verb RunAs -Wait

Write-Host "The device restart is complete. FTDI settings have taken effect." -ForegroundColor Green

### --- [Step 5] Run firmware burn script (download.bat), with logging and error check ---

# Check if valid FTDI bus VID/PID were obtained
if (-not $instanceId) {
    Write-Log "Failed to obtain FTDI bus VID/PID."
    exit 1
}

Write-Log "..."
Write-Log ".. Wi-Fi Firmware programming .."
$downloadBat = Join-Path -Path $PSScriptRoot -ChildPath "..\\Files\\download.bat"
$downloadBatDir = Split-Path $downloadBat -Parent
# $output_Program = & $downloadBat *>> "$logDir\$Output_Txtfile"
#Start-Process -FilePath $downloadBat -Wait -NoNewWindow -RedirectStandardOutput "$logDir\$Output_Txtfile"
#Start-Process -FilePath $downloadBat -ArgumentList $COMPORT -Wait -NoNewWindow -RedirectStandardOutput "$logDir\$Output_Txtfile"
Start-Process -FilePath $downloadBat -ArgumentList $COMPORT -Wait -NoNewWindow -WorkingDirectory $downloadBatDir -RedirectStandardOutput "$logDir\$Output_Txtfile"
$output_Program | Out-File -FilePath $OutputFilePath -Append
Check-Error

# Final success message
Write-Log "....."
Write-Log "Device programmed successfully ..."

### --- [Step 6] Restore LatencyTimer = 16 and finalize log output with standardized filename ---

# Setting the Registry Path and Latency Values to 16
Set-ItemProperty -Path $registryPath -Name "LatencyTimer" -Value 16

# Copy Process Log with MAC as Standard naming format file
Copy-Item -Path $OutputFilePath -Destination (Join-Path $logDir $StandardOutput_Txtfile) -Force

Write-Log "Done."
