param(
    [int]$Port = 8797,
    [string]$BindAddress = "127.0.0.1"
)

$ErrorActionPreference = "Stop"
$root = Split-Path -Parent $PSScriptRoot
$runtime = Join-Path $root "runtime"
$logs = Join-Path $runtime "logs"
$cache = Join-Path $runtime "cache\python"
New-Item -ItemType Directory -Force -Path $logs, $cache | Out-Null

$launcher = Get-Command py -ErrorAction SilentlyContinue
if (-not $launcher) {
    $launcher = Get-Command python -ErrorAction Stop
}

# PowerShell 5.1 cannot start a child process when the host supplies both
# Windows' canonical "Path" key and an additional case-variant "PATH" key.
$environmentKeys = @([Environment]::GetEnvironmentVariables().Keys)
if (($environmentKeys -ccontains "Path") -and ($environmentKeys -ccontains "PATH")) {
    [Environment]::SetEnvironmentVariable("PATH", $null, [EnvironmentVariableTarget]::Process)
}

$env:PYTHONPYCACHEPREFIX = $cache
$stdout = Join-Path $logs "server-$Port.log"
$stderr = Join-Path $logs "server-$Port.err.log"

function Get-ListeningProcessId {
    param([int]$LocalPort)

    $pattern = "^\s*TCP\s+\S+:$LocalPort\s+\S+\s+LISTENING\s+(\d+)\s*$"
    $match = netstat -ano -p TCP | Select-String -Pattern $pattern | Select-Object -First 1
    if ($match) {
        return [int]$match.Matches[0].Groups[1].Value
    }
    return $null
}

$pidFile = Join-Path $runtime "server-$Port.pid"
$serverProcessId = Get-ListeningProcessId -LocalPort $Port
if ($serverProcessId) {
    Set-Content -LiteralPath $pidFile -Value $serverProcessId -Encoding ascii
    Write-Output "Already running PID ${serverProcessId}: http://${BindAddress}:$Port/"
    Write-Output "Logs: $stdout"
    exit 0
}

$childCommand = "& '$($launcher.Source.Replace("'", "''"))' -u server.py --host '$($BindAddress.Replace("'", "''"))' --port $Port 1> '$($stdout.Replace("'", "''"))' 2> '$($stderr.Replace("'", "''"))'"
$encodedCommand = [Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($childCommand))
$process = Start-Process `
    -FilePath (Join-Path $PSHOME "powershell.exe") `
    -ArgumentList @("-NoProfile", "-ExecutionPolicy", "Bypass", "-EncodedCommand", $encodedCommand) `
    -WorkingDirectory $root `
    -WindowStyle Hidden `
    -PassThru

$serverProcessId = $null
for ($attempt = 0; $attempt -lt 100; $attempt++) {
    $listeningProcessId = Get-ListeningProcessId -LocalPort $Port
    if ($listeningProcessId) {
        $serverProcessId = $listeningProcessId
        break
    }
    if ($process.HasExited) {
        break
    }
    Start-Sleep -Milliseconds 100
}
if (-not $serverProcessId) {
    $detail = Get-Content -LiteralPath $stderr -Raw -ErrorAction SilentlyContinue
    throw "Server did not listen on port $Port. $detail"
}

Set-Content -LiteralPath $pidFile -Value $serverProcessId -Encoding ascii
Write-Output "Started PID ${serverProcessId}: http://${BindAddress}:$Port/"
Write-Output "Logs: $stdout"
