# ArcIn Connector Agent - Windows diagnostic script
#
# Self-elevates to Administrator, captures binary startup output,
# checks agent.yaml values, and tests control plane connectivity.
#
# Run from any PowerShell window (elevation handled automatically):
#   powershell -ExecutionPolicy Bypass -File .\diagnose-agent-windows.ps1

$ErrorActionPreference = 'Stop'

$ServiceName = 'ArcInAgent'
$BinaryPath  = "$env:ProgramFiles\ArcInAgent\arcin-agent.exe"
$ConfigFile  = "$env:ProgramData\ArcInAgent\agent.yaml"
$StdoutLog   = "$env:TEMP\arcin-diag-stdout.txt"
$StderrLog   = "$env:TEMP\arcin-diag-stderr.txt"

# ── Self-elevate if not running as Administrator ────────────────────────────────
$id = [Security.Principal.WindowsIdentity]::GetCurrent()
$p  = New-Object Security.Principal.WindowsPrincipal($id)
if (-not $p.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
    Write-Host "Not running as Administrator - re-launching elevated..." -ForegroundColor Yellow
    Start-Process powershell.exe `
        -ArgumentList "-ExecutionPolicy Bypass -File `"$PSCommandPath`"" `
        -Verb RunAs
    exit
}

Write-Host "============================================" -ForegroundColor Cyan
Write-Host "  ArcIn Agent Diagnostic" -ForegroundColor Cyan
Write-Host "============================================`n" -ForegroundColor Cyan

# ── 1. Binary ──────────────────────────────────────────────────────────────────
Write-Host "[1] Binary" -ForegroundColor Yellow
if (Test-Path $BinaryPath) {
    $v = & $BinaryPath --version 2>&1
    Write-Host "    Found : $BinaryPath"
    Write-Host "    Version: $v"
} else {
    Write-Host "    MISSING: $BinaryPath" -ForegroundColor Red
}

# ── 2. Service registration ────────────────────────────────────────────────────
Write-Host "`n[2] Service registration" -ForegroundColor Yellow
$svc = Get-Service -Name $ServiceName -ErrorAction SilentlyContinue
if ($svc) {
    Write-Host "    Status     : $($svc.Status)"
    Write-Host "    StartType  : $($svc.StartType)"
    $cfg = & sc.exe qc $ServiceName 2>&1
    ($cfg | Select-String 'BINARY_PATH_NAME|SERVICE_START_NAME').Line |
        ForEach-Object { Write-Host "    $_" }
} else {
    Write-Host "    MISSING - service is not registered." -ForegroundColor Red
}

# ── 3. Config file ─────────────────────────────────────────────────────────────
Write-Host "`n[3] Config file" -ForegroundColor Yellow

# Reset ACL temporarily so we can read it, then restore
$aclRestored = $false
try {
    & takeown /F $ConfigFile /A 2>&1 | Out-Null
    & icacls $ConfigFile /grant Administrators:R /C /Q 2>&1 | Out-Null
    $aclRestored = $true
} catch {}

if (Test-Path $ConfigFile) {
    $raw = Get-Content $ConfigFile -Raw -ErrorAction SilentlyContinue
    if ($raw) {
        # Redact token value before printing
        $redacted = $raw -replace '(?i)(token\s*:\s*")[^"]+(")', '$1***REDACTED***$2'
        $redacted = $redacted -replace "(?i)(token\s*:\s*)'[^']+'", "token: '***REDACTED***'"
        $redacted = $redacted -replace '(?i)(token\s*:\s*)(?!REPLACE_ME)(\S+)', '$1***REDACTED***'
        Write-Host $redacted
    } else {
        Write-Host "    Could not read config (ACL may still be locked)." -ForegroundColor Red
    }
} else {
    Write-Host "    MISSING: $ConfigFile" -ForegroundColor Red
}

# ── 4. Run binary directly and capture output ──────────────────────────────────
Write-Host "`n[4] Binary startup output (5 second run)" -ForegroundColor Yellow
if (Test-Path $BinaryPath) {
    if (Test-Path $StdoutLog) { Remove-Item $StdoutLog -Force }
    if (Test-Path $StderrLog) { Remove-Item $StderrLog -Force }

    $proc = Start-Process -FilePath $BinaryPath `
        -ArgumentList "--config `"$ConfigFile`"" `
        -RedirectStandardOutput $StdoutLog `
        -RedirectStandardError  $StderrLog `
        -NoNewWindow -PassThru

    # Let it run for 5 seconds then check
    Start-Sleep -Seconds 5
    $exited = $proc.HasExited

    if (-not $exited) {
        $proc.Kill()
        Write-Host "    Binary ran for 5s without exiting (process was still alive - killed for diagnostic)." -ForegroundColor Yellow
    } else {
        Write-Host "    Binary exited in < 5s with exit code: $($proc.ExitCode)"
    }

    $stdout = Get-Content $StdoutLog -ErrorAction SilentlyContinue
    $stderr = Get-Content $StderrLog -ErrorAction SilentlyContinue

    if ($stdout) { Write-Host "`n    --- stdout ---"; $stdout | ForEach-Object { Write-Host "    $_" } }
    if ($stderr) { Write-Host "`n    --- stderr ---"; $stderr | ForEach-Object { Write-Host "    $_" -ForegroundColor Red } }
    if (-not $stdout -and -not $stderr) { Write-Host "    (no output captured)" }
}

# ── 5. Control plane connectivity ──────────────────────────────────────────────
Write-Host "`n[5] Control plane connectivity" -ForegroundColor Yellow
$cpUrl = $null
if (Test-Path $ConfigFile) {
    $cfgContent = Get-Content $ConfigFile -ErrorAction SilentlyContinue
    $urlLine = $cfgContent | Select-String '^\s*url:\s*"?(wss?://[^"]+)"?' | Select-Object -First 1
    if ($urlLine) {
        $cpUrl = ($urlLine -replace '.*url:\s*"?(wss?://[^"]+)"?.*', '$1').Trim()
    }
}

if ($cpUrl) {
    Write-Host "    control_plane.url: $cpUrl"
    # Convert wss:// to https:// for TCP test
    $httpUrl = $cpUrl -replace '^wss://', 'https://' -replace '^ws://', 'http://'
    $uri     = [System.Uri]$httpUrl
    $host_   = $uri.Host
    $port    = if ($uri.Port -gt 0) { $uri.Port } else { if ($uri.Scheme -eq 'https') { 443 } else { 80 } }

    Write-Host "    Testing TCP $host_`:$port ..."
    $tcp = New-Object System.Net.Sockets.TcpClient
    try {
        $ar = $tcp.BeginConnect($host_, $port, $null, $null)
        $ok = $ar.AsyncWaitHandle.WaitOne(5000)
        if ($ok -and $tcp.Connected) {
            Write-Host "    TCP connection: OK" -ForegroundColor Green
        } else {
            Write-Host "    TCP connection: FAILED (timeout or refused) - check URL and firewall" -ForegroundColor Red
        }
    } catch {
        Write-Host "    TCP connection: FAILED - $($_.Exception.Message)" -ForegroundColor Red
    } finally {
        $tcp.Close()
    }
} else {
    Write-Host "    Could not parse control_plane.url from config." -ForegroundColor Red
}

# ── 6. Event log ───────────────────────────────────────────────────────────────
Write-Host "`n[6] Recent event log entries" -ForegroundColor Yellow
Get-EventLog -LogName System -Source "Service Control Manager" -Newest 5 -ErrorAction SilentlyContinue |
    Where-Object { $_.Message -like "*ArcInAgent*" -or $_.Message -like "*ArcIn*" } |
    ForEach-Object { Write-Host "    [$($_.EntryType)] $($_.TimeGenerated) - $($_.Message.Split([char]10)[0])" }

Write-Host "`n============================================" -ForegroundColor Cyan
Write-Host "  Diagnostic complete." -ForegroundColor Cyan
Write-Host "============================================`n" -ForegroundColor Cyan
Read-Host "Press Enter to close"
