@echo off
REM ============================================================================
REM  Setup-Remote-Support.bat   --   Oat Hosting remote support installer
REM
REM  Single-file package. The end user double-clicks this; everything below the
REM  #PS''CODE# marker is PowerShell, extracted and run at launch.
REM
REM  Writes RustDesk2.toml directly rather than relying on --config, which does
REM  not reliably apply on 1.4.x. Config is written to BOTH the user profile and
REM  the LocalService profile, because the background service reads its own copy.
REM
REM  Log: %TEMP%\RemoteSupport\setup.log
REM ============================================================================
set "RD_BAT=%~f0"
powershell -NoProfile -ExecutionPolicy Bypass -Command "$m='#PS'+'CODE#'; $s=Get-Content -LiteralPath '%~f0' -Raw; iex $s.Substring($s.IndexOf($m)+$m.Length)"
if errorlevel 1 (
  echo.
  echo Setup did not finish. Log: %%TEMP%%\RemoteSupport\setup.log
  pause
)
exit /b
#PSCODE#

# ---------------------------------------------------------------- CONFIG ----
$IdServer    = "rustdesk.oathosting.com"
$RelayServer = "rustdesk.oathosting.com"
$PublicKey   = "o0Z4JzM2w98Oddlydld2TssQUeoyHLkI7RcrKV5m0vY="
$ApiServer   = ""            # OSS server has no API/web console -- leave blank
$SupportName = "Oat Hosting"
# -----------------------------------------------------------------------------

$ErrorActionPreference = 'Continue'

$workDir = Join-Path $env:TEMP "RemoteSupport"
New-Item -ItemType Directory -Force -Path $workDir | Out-Null
$logFile = Join-Path $workDir "setup.log"

function Log($msg) {
    Add-Content -Path $logFile -Value "$(Get-Date -Format 'HH:mm:ss')  $msg" -ErrorAction SilentlyContinue
}

function Write-Title($text) {
    Write-Host ""
    Write-Host ("=" * 62) -ForegroundColor Cyan
    Write-Host "  $text" -ForegroundColor Cyan
    Write-Host ("=" * 62) -ForegroundColor Cyan
    Write-Host ""
}

function Fail($msg) {
    Log "FAILED: $msg"
    Write-Host ""
    Write-Host " Setup could not complete." -ForegroundColor Red
    Write-Host ""
    Write-Host " $msg" -ForegroundColor Yellow
    Write-Host ""
    Write-Host " Log: $logFile" -ForegroundColor Gray
    Write-Host ""
    Read-Host " Press Enter to close"
    exit 1
}

# TOML body written to every config location
function Get-ConfigToml {
@"
rendezvous_server = '$IdServer'
nat_type = 1
serial = 0

[options]
custom-rendezvous-server = '$IdServer'
key = '$PublicKey'
relay-server = '$RelayServer'
api-server = '$ApiServer'
"@
}

# Run a rustdesk sub-command, but never block forever if it decides to stay open
function Invoke-RustDesk($exePath, [string[]]$rdArgs, $timeoutSec = 60) {
    $proc = Start-Process -FilePath $exePath -ArgumentList $rdArgs -PassThru
    try {
        Wait-Process -Id $proc.Id -Timeout $timeoutSec -ErrorAction Stop
        Log "  ran $($rdArgs -join ' ') -> exited"
    } catch {
        Log "  ran $($rdArgs -join ' ') -> still running after ${timeoutSec}s, killing"
        try { Stop-Process -Id $proc.Id -Force -ErrorAction SilentlyContinue } catch {}
    }
}

function Write-ConfigTo($path) {
    try {
        $dir = Split-Path $path -Parent
        New-Item -ItemType Directory -Force -Path $dir | Out-Null
        Set-Content -Path $path -Value (Get-ConfigToml) -Encoding UTF8 -Force
        Log "Wrote config: $path"
        return $true
    } catch {
        Log "Could not write $path : $($_.Exception.Message)"
        return $false
    }
}

Log "=== Run started. PS=$($PSVersionTable.PSVersion) ==="

# --- Elevate ------------------------------------------------------------------
$isAdmin = ([Security.Principal.WindowsPrincipal] `
            [Security.Principal.WindowsIdentity]::GetCurrent() `
           ).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
Log "IsAdmin=$isAdmin"

if (-not $isAdmin) {
    $bat = $env:RD_BAT
    if (-not $bat) { $bat = $MyInvocation.MyCommand.Path }
    Write-Host "Requesting administrator permission..." -ForegroundColor Yellow
    try {
        Start-Process -FilePath "cmd.exe" -ArgumentList "/c", "`"$bat`"" -Verb RunAs -ErrorAction Stop
    } catch {
        Write-Host "Administrator permission was declined. Cannot continue." -ForegroundColor Red
        Read-Host "Press Enter to close"
    }
    exit
}

try {

    Write-Title "$SupportName Remote Support Setup"
    Write-Host "  How should this computer be set up?"
    Write-Host ""
    Write-Host "   [1] Ongoing support  " -NoNewline -ForegroundColor Green
    Write-Host "- installs so your technician can connect"
    Write-Host "                          when needed."
    Write-Host ""
    Write-Host "   [2] One-time session " -NoNewline -ForegroundColor Green
    Write-Host "- nothing installed, runs once for this call."
    Write-Host ""

    do { $mode = Read-Host "  Enter 1 or 2" } until ($mode -eq '1' -or $mode -eq '2')
    Log "Mode: $mode"

    # --- Download -------------------------------------------------------------
    Write-Host ""
    Write-Host "Downloading remote support software..." -ForegroundColor Cyan
    [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12

    try {
        $release = Invoke-RestMethod -Uri 'https://api.github.com/repos/rustdesk/rustdesk/releases/latest' `
                                     -Headers @{ 'User-Agent' = 'PowerShell' } -ErrorAction Stop
    } catch {
        Fail "Could not reach the download server. Check the internet connection."
    }

    $asset = $release.assets | Where-Object { $_.name -match '^rustdesk-[0-9.]+-x86_64\.exe$' } | Select-Object -First 1
    if (-not $asset) { Fail "No Windows installer found in the latest release." }
    Log "Asset: $($asset.name)"

    $exe = Join-Path $workDir "rustdesk.exe"
    $ProgressPreference = 'SilentlyContinue'
    try { Invoke-WebRequest $asset.browser_download_url -OutFile $exe -ErrorAction Stop }
    catch { Fail "Download failed. ($($_.Exception.Message))" }
    $ProgressPreference = 'Continue'
    Log "Downloaded $((Get-Item $exe).Length) bytes"

    # =========================== MODE 2: ONE-TIME ============================
    if ($mode -eq '2') {
        Write-Host "Preparing one-time session..." -ForegroundColor Cyan

        # Portable client reads the config of the user running it
        Write-ConfigTo (Join-Path $env:APPDATA "RustDesk\config\RustDesk2.toml") | Out-Null

        Write-Title "Ready"
        Write-Host "  The support window is opening now."
        Write-Host ""
        Write-Host "  Read the " -NoNewline
        Write-Host "ID" -NoNewline -ForegroundColor Yellow
        Write-Host " and " -NoNewline
        Write-Host "Password" -NoNewline -ForegroundColor Yellow
        Write-Host " shown in that window to your technician."
        Write-Host ""
        Write-Host "  Close the window when finished. Nothing was installed."
        Write-Host ""

        Start-Process -FilePath $exe
        Start-Sleep -Seconds 3
        Log "Mode 2 complete"
        Read-Host "  Press Enter to close"
        exit 0
    }

    # ========================== MODE 1: UNATTENDED ===========================
    Write-Host "Installing (about a minute)..." -ForegroundColor Cyan

    # NOTE: do NOT use -Wait here. --silent-install completes but then launches
    # the RustDesk GUI, so the process never exits and -Wait hangs forever.
    # Poll for the installed binary instead.
    Start-Process -FilePath $exe -ArgumentList "--silent-install" | Out-Null
    Log "Installer launched (not waiting on process)"

    $candidates = @(
        (Join-Path $env:ProgramFiles "RustDesk\rustdesk.exe"),
        (Join-Path ${env:ProgramFiles(x86)} "RustDesk\rustdesk.exe"),
        (Join-Path $env:LOCALAPPDATA "Programs\RustDesk\rustdesk.exe")
    ) | Where-Object { $_ }

    $rdExe = $null
    $waited = 0
    while (-not $rdExe -and $waited -lt 180) {
        Start-Sleep -Seconds 3
        $waited += 3
        $rdExe = $candidates | Where-Object { Test-Path $_ } | Select-Object -First 1
        if (($waited % 15) -eq 0) { Write-Host "  still installing... ($waited seconds)" -ForegroundColor DarkGray }
    }

    if (-not $rdExe) {
        Fail "The installer did not complete after 3 minutes. Antivirus or a Windows security prompt may have blocked it."
    }
    Log "rustdesk.exe found at $rdExe after $waited seconds"

    # Give the installer a moment to finish writing, then close the GUI it opened
    Start-Sleep -Seconds 5
    Get-Process rustdesk -ErrorAction SilentlyContinue | Stop-Process -Force -ErrorAction SilentlyContinue
    Start-Sleep -Seconds 2

    # Service must exist before we stop it
    if (-not (Get-Service -Name 'RustDesk' -ErrorAction SilentlyContinue)) {
        Write-Host "Registering background service..." -ForegroundColor Cyan
        Invoke-RustDesk $rdExe @("--install-service") 90
        Start-Sleep -Seconds 10
    }

    # --- Stop everything before touching config -------------------------------
    Write-Host "Applying support settings..." -ForegroundColor Cyan
    Log "Stopping service and processes"
    try { Stop-Service 'RustDesk' -Force -ErrorAction Stop } catch { Log "Stop-Service: $($_.Exception.Message)" }
    Get-Process rustdesk -ErrorAction SilentlyContinue | Stop-Process -Force -ErrorAction SilentlyContinue
    Start-Sleep -Seconds 3

    # --- Write config to every place that matters -----------------------------
    # 1) LocalService profile -- what the background service reads
    $svcCfg = Join-Path $env:WINDIR "ServiceProfiles\LocalService\AppData\Roaming\RustDesk\config\RustDesk2.toml"
    $okSvc = Write-ConfigTo $svcCfg

    # 2) The console user's profile -- what the GUI reads
    $consoleUser = $null
    try {
        $cs = Get-CimInstance -ClassName Win32_ComputerSystem -ErrorAction Stop
        if ($cs.UserName) { $consoleUser = ($cs.UserName -split '\\')[-1] }
    } catch { Log "Win32_ComputerSystem lookup failed: $($_.Exception.Message)" }
    if (-not $consoleUser) { $consoleUser = $env:USERNAME }
    Log "Console user: $consoleUser"

    $userCfg = Join-Path $env:SystemDrive "Users\$consoleUser\AppData\Roaming\RustDesk\config\RustDesk2.toml"
    $okUser = Write-ConfigTo $userCfg

    if (-not $okSvc) { Fail "Could not write the service configuration at $svcCfg" }

    # --- Password (service stopped) -------------------------------------------
    $pw = -join ((65..90) + (97..122) + (48..57) | Get-Random -Count 12 | ForEach-Object { [char]$_ })
    Invoke-RustDesk $rdExe @("--password", $pw) 45
    Start-Sleep -Seconds 2
    Log "Password set"

    # --- Restart and verify ----------------------------------------------------
    try { Start-Service 'RustDesk' -ErrorAction Stop } catch { Log "Start-Service: $($_.Exception.Message)" }
    Start-Sleep -Seconds 8

    $verify = ""
    if (Test-Path $svcCfg) { $verify = (Get-Content $svcCfg -Raw) }
    if ($verify -notmatch [regex]::Escape($IdServer)) {
        Fail "Configuration was written but did not take effect. Check $svcCfg"
    }
    Log "Verified $IdServer present in service config"

    $id = (& $rdExe --get-id 2>&1 | Out-String).Trim()
    Log "ID: '$id'"
    if (-not $id) { Fail "Could not read the computer ID. Open RustDesk manually to check." }

    $outFile = Join-Path ([Environment]::GetFolderPath('Desktop')) "Remote Support Details.txt"
    @"
$SupportName - Remote Support Details
Generated: $(Get-Date -Format 'yyyy-MM-dd HH:mm')
Computer:  $env:COMPUTERNAME

  ID:       $id
  Password: $pw
  Server:   $IdServer

Give these details to your technician. Keep this file somewhere safe --
anyone with the ID and password can connect to this computer.
"@ | Set-Content -Path $outFile -Encoding UTF8

    Write-Title "Setup Complete"
    Write-Host "  Give these details to your technician:"
    Write-Host ""
    Write-Host "     ID:       " -NoNewline; Write-Host $id -ForegroundColor Yellow
    Write-Host "     Password: " -NoNewline; Write-Host $pw -ForegroundColor Yellow
    Write-Host ""
    Write-Host "  Saved to your Desktop as 'Remote Support Details.txt'" -ForegroundColor Gray
    Write-Host ""
    Write-Host "  To remove later, uninstall RustDesk from Add/Remove Programs."
    Write-Host ""
    Log "Complete. ID=$id"

    Read-Host "  Press Enter to close"

} catch {
    Log "UNHANDLED: $($_.Exception.Message)"
    Log "At: $($_.InvocationInfo.PositionMessage)"
    Write-Host ""
    Write-Host " Unexpected error:" -ForegroundColor Red
    Write-Host " $($_.Exception.Message)" -ForegroundColor Yellow
    Write-Host " $($_.InvocationInfo.PositionMessage)" -ForegroundColor DarkGray
    Write-Host ""
    Write-Host " Log: $logFile" -ForegroundColor Gray
    Read-Host " Press Enter to close"
    exit 1
}
