@echo off
set "BL_SCRIPT_DIR=%~dp0"
set "BL_PS=%TEMP%\bl-https-%RANDOM%.ps1"
rem Clear inherited pwsh module paths so PowerShell 5.1 can mount Cert: (PowerShell/PowerShell#18530)
set "PSModulePath="
more +9 "%~f0" > "%BL_PS%"
powershell -NoProfile -ExecutionPolicy Bypass -File "%BL_PS%" %*
del "%BL_PS%" 2>nul
exit /b
#Requires -Version 5.1
# NOTE: installer-files/ overlay fork of the upstream artifact start-https.bat (assemble.sh Step 4 overwrites the artifact copy with this one). Divergences from upstream: (1) the $StartPort definition below, added so the startup echo prints a real port; (2) the bundled-runtime detection block below, which lets an offline installer use a pre-verified node.exe instead of downloading -- push the same fixes upstream eventually.
$ErrorActionPreference = "Stop"
$ScriptDir = if ($env:BL_SCRIPT_DIR) { $env:BL_SCRIPT_DIR } else { $PSScriptRoot }
Set-Location -LiteralPath $ScriptDir

# Production serve of the packaged build — server.js also defaults this, but be
# explicit so a future server change can't regress to dev mode (IRT-1316).
$env:NODE_ENV = "production"

# ── Load webadmin.conf defaults (env vars take precedence) ────────────────────
$confPath = Join-Path $ScriptDir "webadmin.conf"
if (Test-Path $confPath) {
    Get-Content $confPath | Where-Object { $_ -notmatch '^\s*#' -and $_ -match '=' } | ForEach-Object {
        $parts = $_ -split '=', 2
        $k = $parts[0].Trim()
        $v = if ($parts.Count -gt 1) { $parts[1].Trim() } else { "" }
        if ($k -and -not [System.Environment]::GetEnvironmentVariable($k)) {
            [System.Environment]::SetEnvironmentVariable($k, $v, "Process")
        }
    }
}

Write-Host ""
Write-Host " BridgeLink Web UI -- HTTPS" -ForegroundColor Cyan
Write-Host " ===========================" -ForegroundColor Cyan
Write-Host ""

# ── Ensure Node.js 22 ─────────────────────────────────────────────────────────
# Store Node + certs under %LOCALAPPDATA%\BridgeLink\ so the script runs
# without admin rights even when BridgeLink is installed in a location like
# C:\Program Files\... that the current user can't write to.
$NodeVersion = "22.22.2"
$NodeDir     = Join-Path $env:LOCALAPPDATA "BridgeLink\.node"
$LocalNode   = Join-Path $NodeDir "node.exe"

function Test-NodeOk([string]$Exe) {
    if ($Exe -eq "node") {
        if (-not (Get-Command node -ErrorAction SilentlyContinue)) { return $false }
    } else {
        if (-not (Test-Path -LiteralPath $Exe)) { return $false }
    }
    $prev = $ErrorActionPreference; $ErrorActionPreference = "Continue"
    & $Exe -e "process.exit(parseInt(process.versions.node)>=22?0:1)" 2>$null | Out-Null
    $ok = ($LASTEXITCODE -eq 0)
    $ErrorActionPreference = $prev
    return $ok
}

$BundledNode = Join-Path $ScriptDir "node-runtime\node.exe"
$BundledHash = Join-Path $ScriptDir "node-runtime\node.exe.sha256"
if ((Test-Path -LiteralPath $BundledNode) -and -not (Test-NodeOk $LocalNode) -and -not (Test-NodeOk "node")) {
    $expectedHash = (Get-Content $BundledHash -Raw).Trim().ToLower()
    $actualHash   = (Get-FileHash -Algorithm SHA256 -Path $BundledNode).Hash.ToLower()
    if ($actualHash -eq $expectedHash) {
        New-Item -ItemType Directory -Force -Path $NodeDir | Out-Null
        Copy-Item $BundledNode $LocalNode -Force
        $NodeExe = $LocalNode
        Write-Host " Using bundled Node.js runtime (offline installer) -- no download." -ForegroundColor Green
    }
}

if (Test-NodeOk $LocalNode) {
    $NodeExe = $LocalNode
} elseif (Test-NodeOk "node") {
    $NodeExe = "node"
} else {
    Write-Host " Node.js 22 not found -- downloading (one-time setup)..." -ForegroundColor Yellow
    $ZipPath    = Join-Path $env:TEMP "bl-node-win.zip"
    $ExtractDir = Join-Path $env:TEMP "bl-node-win"

    New-Item -ItemType Directory -Force -Path $NodeDir | Out-Null
    Write-Host " Downloading Node.js $NodeVersion from nodejs.org..." -ForegroundColor Yellow
    try {
        Invoke-WebRequest -Uri "https://nodejs.org/dist/v$NodeVersion/node-v$NodeVersion-win-x64.zip" `
            -OutFile $ZipPath -UseBasicParsing
    } catch {
        Write-Host " [ERROR] Download failed: $($_.Exception.Message)" -ForegroundColor Red
        Write-Host " Check your internet connection and try again."
        Read-Host "`nPress Enter to exit"
        exit 1
    }

    # Verify SHA256 integrity against official SHASUMS256.txt before extracting
    Write-Host " Verifying Node.js download integrity..." -ForegroundColor Yellow
    try {
        $Sha256Url = "https://nodejs.org/dist/v$NodeVersion/SHASUMS256.txt"
        $Shasums   = (Invoke-WebRequest -Uri $Sha256Url -UseBasicParsing).Content
    } catch {
        Write-Host " [ERROR] Node.js download integrity check FAILED: could not fetch SHASUMS256.txt ($($_.Exception.Message))" -ForegroundColor Red
        Remove-Item $ZipPath -Force -ErrorAction SilentlyContinue
        Read-Host "`nPress Enter to exit"
        exit 1
    }
    $Expected = ($Shasums -split "`n" | Where-Object { $_ -match "node-v$NodeVersion-win-x64\.zip" }) -replace '\s.*', ''
    $Actual   = (Get-FileHash -Algorithm SHA256 -Path $ZipPath).Hash.ToLower()
    if ($Actual -ne $Expected.Trim().ToLower()) {
        Write-Host " [ERROR] Node.js download integrity check FAILED. Expected: $Expected  Got: $Actual" -ForegroundColor Red
        Remove-Item $ZipPath -Force -ErrorAction SilentlyContinue
        Read-Host "`nPress Enter to exit"
        exit 1
    }
    Write-Host " Node.js download integrity verified." -ForegroundColor Green

    Write-Host " Extracting..." -ForegroundColor Yellow
    Expand-Archive -Path $ZipPath -DestinationPath $ExtractDir -Force
    Copy-Item (Join-Path $ExtractDir "node-v$NodeVersion-win-x64\node.exe") `
              (Join-Path $NodeDir "node.exe") -Force
    Remove-Item $ZipPath    -Force -ErrorAction SilentlyContinue
    Remove-Item $ExtractDir -Recurse -Force -ErrorAction SilentlyContinue
    $NodeExe = $LocalNode

    # Add .node to the current user's PATH so future terminals find 'node' directly
    $userPath = [Environment]::GetEnvironmentVariable("PATH", "User")
    if ($userPath -notlike "*$NodeDir*") {
        [Environment]::SetEnvironmentVariable("PATH", "$NodeDir;$userPath", "User")
        $env:PATH = "$NodeDir;$env:PATH"
        Write-Host " Added .node to your PATH (takes effect in new terminals)." -ForegroundColor Green
    }

    Write-Host " Node.js $NodeVersion ready." -ForegroundColor Green
    Write-Host ""
}

# ── Ensure TLS certificate ─────────────────────────────────────────────────────
$CertsDir = Join-Path $env:LOCALAPPDATA "BridgeLink\certs"
$CertFile = Join-Path $CertsDir "server.crt"
$KeyFile  = Join-Path $CertsDir "server.key"

if (-not (Test-Path $CertFile) -or -not (Test-Path $KeyFile)) {
    Write-Host " Certificate not found -- generating self-signed certificate..." -ForegroundColor Yellow
    New-Item -ItemType Directory -Force -Path $CertsDir | Out-Null

    # Find OpenSSL in PATH or common install locations
    $OpenSSL = $null
    $sslCmd  = Get-Command openssl -ErrorAction SilentlyContinue
    if ($sslCmd) {
        $OpenSSL = $sslCmd.Source
    } else {
        @(
            "C:\Program Files\Git\usr\bin\openssl.exe",
            "C:\Program Files\OpenSSL-Win64\bin\openssl.exe",
            "C:\Program Files\OpenSSL\bin\openssl.exe",
            "C:\OpenSSL-Win64\bin\openssl.exe"
        ) | ForEach-Object { if (-not $OpenSSL -and (Test-Path $_)) { $OpenSSL = $_ } }
    }

    if ($OpenSSL) {
        Write-Host " Using OpenSSL: $OpenSSL" -ForegroundColor Yellow
        $prev = $ErrorActionPreference; $ErrorActionPreference = "Continue"
        # Try with SAN extension first (OpenSSL 1.1.1+)
        & $OpenSSL req -x509 -newkey rsa:2048 -sha256 -days 3650 -nodes `
            -keyout $KeyFile -out $CertFile `
            -subj "/CN=localhost" `
            -addext "subjectAltName=DNS:localhost,IP:127.0.0.1" 2>&1 | Out-Null
        if ($LASTEXITCODE -ne 0) {
            # Fallback for older OpenSSL without -addext
            & $OpenSSL req -x509 -newkey rsa:2048 -sha256 -days 3650 -nodes `
                -keyout $KeyFile -out $CertFile -subj "/CN=localhost" 2>&1 | Out-Null
        }
        $ErrorActionPreference = $prev
        if (-not (Test-Path $CertFile)) {
            Write-Host " [ERROR] OpenSSL failed to generate the certificate." -ForegroundColor Red
            Read-Host "`nPress Enter to exit"; exit 1
        }
        Write-Host " Certificate generated (via OpenSSL)." -ForegroundColor Green
    } else {
        # PowerShell fallback -- no OpenSSL required
        Write-Host " OpenSSL not found -- generating via PowerShell..." -ForegroundColor Yellow
        try {
            $cert = New-SelfSignedCertificate `
                -DnsName "localhost" `
                -CertStoreLocation "Cert:\CurrentUser\My" `
                -NotAfter (Get-Date).AddYears(10) `
                -KeyAlgorithm RSA -KeyLength 2048 -HashAlgorithm SHA256 `
                -KeyExportPolicy Exportable

            # Export certificate (DER -> PEM)
            $certDer = $cert.Export(
                [System.Security.Cryptography.X509Certificates.X509ContentType]::Cert)
            $certB64 = [Convert]::ToBase64String(
                $certDer, [System.Base64FormattingOptions]::InsertLineBreaks)
            "-----BEGIN CERTIFICATE-----`r`n$certB64`r`n-----END CERTIFICATE-----" |
                Set-Content -Path $CertFile -Encoding ASCII

            # Export private key (CNG PKCS#8 -> PEM)
            $rsa    = [System.Security.Cryptography.X509Certificates.RSACertificateExtensions]::GetRSAPrivateKey($cert)
            $keyDer = $rsa.Key.Export([System.Security.Cryptography.CngKeyBlobFormat]::Pkcs8PrivateBlob)
            $keyB64 = [Convert]::ToBase64String(
                $keyDer, [System.Base64FormattingOptions]::InsertLineBreaks)
            "-----BEGIN PRIVATE KEY-----`r`n$keyB64`r`n-----END PRIVATE KEY-----" |
                Set-Content -Path $KeyFile -Encoding ASCII

            Write-Host " Certificate generated (via PowerShell)." -ForegroundColor Green
        } catch {
            Write-Host " [ERROR] Could not generate certificate: $($_.Exception.Message)" -ForegroundColor Red
            Write-Host ""
            Write-Host " Install Git for Windows (includes OpenSSL) and re-run:" -ForegroundColor Yellow
            Write-Host "   https://git-scm.com/download/win" -ForegroundColor Yellow
            Read-Host "`nPress Enter to exit"; exit 1
        }
    }

}

# ── Trust the certificate if it isn't already trusted ──────────────────────────
# Runs even when the cert already exists -- e.g. it was generated by an earlier
# run but never trusted, or the trust prompt was declined once. A pre-existing
# but untrusted cert otherwise leaves the browser unable to load subresources
# (blank page), with no "proceed anyway" bypass once HSTS is in play. Uses the
# CurrentUser store so no admin elevation is required.
# The Cert: drive is mounted by the Microsoft.PowerShell.Security module; when a
# polluted PSModulePath breaks its auto-load (PowerShell/PowerShell#18530), try
# once to load it explicitly. Callers fall back to certutil.exe when this fails.
function Test-CertDriveAvailable {
    if (Get-PSDrive Cert -ErrorAction SilentlyContinue) { return $true }
    Import-Module Microsoft.PowerShell.Security -ErrorAction SilentlyContinue
    return [bool](Get-PSDrive Cert -ErrorAction SilentlyContinue)
}

function Invoke-MaybeTrustCert {
    try {
        $cert  = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2 $CertFile
        $thumb = $cert.Thumbprint
    } catch {
        return
    }
    $certDrive = Test-CertDriveAvailable
    # Already trusted? Skip silently so re-runs stay quiet.
    if ($certDrive) {
        if (Test-Path "Cert:\CurrentUser\Root\$thumb") { return }
    } else {
        $prev = $ErrorActionPreference; $ErrorActionPreference = "Continue"
        certutil.exe -user -verifystore Root $thumb 2>&1 | Out-Null
        $alreadyTrusted = ($LASTEXITCODE -eq 0)
        $ErrorActionPreference = $prev
        if ($alreadyTrusted) { return }
    }

    Write-Host ""
    Write-Host " A self-signed certificate is in use for HTTPS but is not yet trusted." -ForegroundColor Yellow
    Write-Host " You can add it to your trust store now to avoid a browser security warning." -ForegroundColor Yellow
    Write-Host " This is optional -- if you skip it, your browser will ask you to confirm" -ForegroundColor Yellow
    Write-Host " before continuing to the page." -ForegroundColor Yellow
    Write-Host ""
    $trust = Read-Host " Add certificate to trust store? (Y/N)"
    if ($trust -match '^[Yy]') {
        $imported = $false
        if ($certDrive) {
            try {
                Import-Certificate -FilePath $CertFile -CertStoreLocation "Cert:\CurrentUser\Root" | Out-Null
                $imported = $true
            } catch {}
        }
        if (-not $imported) {
            # certutil.exe talks to the store directly -- no Cert: drive required.
            $prev = $ErrorActionPreference; $ErrorActionPreference = "Continue"
            certutil.exe -user -addstore Root $CertFile 2>&1 | Out-Null
            $imported = ($LASTEXITCODE -eq 0)
            $ErrorActionPreference = $prev
        }
        if ($imported) {
            Write-Host " Certificate trusted. No browser warning on this machine." -ForegroundColor Green
        } else {
            Write-Host " [WARN] Could not add the certificate to the trust store -- continuing anyway." -ForegroundColor Yellow
            Write-Host " Your browser will prompt you to confirm before loading the page." -ForegroundColor Yellow
        }
    } else {
        Write-Host " Skipped. Your browser will prompt you to confirm before loading the page." -ForegroundColor DarkGray
    }
    Write-Host ""
}

Invoke-MaybeTrustCert

# ── BridgeLink server URL ──────────────────────────────────────────────────────
if (-not $env:BRIDGELINK_SERVER_URL) {
    $env:BRIDGELINK_SERVER_URL = "https://localhost:8443"
}
Write-Host " BridgeLink server: $env:BRIDGELINK_SERVER_URL" -ForegroundColor DarkGray

$env:SSL_CERT_FILE = $CertFile
$env:SSL_KEY_FILE  = $KeyFile

$StartPort = if ($env:PORT) { $env:PORT } else { "3000" }
Write-Host " Starting on https://localhost:$StartPort ..." -ForegroundColor Green
Write-Host " Press Ctrl+C to stop." -ForegroundColor DarkGray
Write-Host ""
& $NodeExe server.js
