@echo off
setlocal EnableExtensions DisableDelayedExpansion

:: E-DA Srl - Installazione automatica RustDesk (Windows 10/11)
:: Doppio clic per avviare (richiede connessione Internet).
:: Chiede SEMPRE il nome con cui registrare il client; la password permanente
:: e' quella fissa E-DA ($PresetPassword nella sezione PowerShell; se vuota la chiede).
:: Per Windows 7/8/8.1 usare install-rustdesk-win7.bat
::
:: Come funziona: questo .bat si limita a chiedere i privilegi di amministratore
:: ed estrae la sezione PowerShell che si trova in fondo al file in un .ps1
:: temporaneo, poi la esegue. Tutta la logica sta nella sezione PowerShell.

:: --- Auto-elevazione a Amministratore ---
net session >nul 2>&1
if %errorlevel% neq 0 (
    echo Avvio con privilegi di amministratore...
    powershell -NoProfile -Command "Start-Process -FilePath '%~f0' -Verb RunAs"
    exit /b
)

set "EDA_BAT=%~f0"
set "EDA_PS1=%TEMP%\eda-rustdesk-install.ps1"

:: --- Estrae la sezione PowerShell in un .ps1 temporaneo (senza BOM) ---
powershell -NoProfile -ExecutionPolicy Bypass -Command "$t=[IO.File]::ReadAllText($env:EDA_BAT); $i=$t.IndexOf('#<'+'EDA-PS1>'); if ($i -lt 0) { exit 9 }; [IO.File]::WriteAllText($env:EDA_PS1, $t.Substring($i), (New-Object Text.UTF8Encoding($false)))"
if errorlevel 1 (
    echo.
    echo  ERRORE: impossibile preparare lo script PowerShell.
    echo.
    pause
    exit /b 1
)

:: --- Esegue la sezione PowerShell ---
powershell -NoProfile -ExecutionPolicy Bypass -File "%EDA_PS1%"
set "RC=%ERRORLEVEL%"
del "%EDA_PS1%" >nul 2>&1

echo.
pause
exit /b %RC%

:: ==========================================================================
:: Da qui in poi il file e' PowerShell: cmd non lo legge mai (esce prima).
:: ==========================================================================
#<EDA-PS1>
# E-DA Srl - Installazione RustDesk: sezione PowerShell (estratta dal .bat)
#
# Sequenza:
#   1. download ultima release (GitHub) e installazione silenziosa
#   2. STOP di tutto: servizio RustDesk + ogni processo rustdesk.exe
#   3. scrittura configurazione E-DA (server/key) nel profilo utente e in
#      quello del servizio, e scrittura della password permanente nel
#      RustDesk.toml del servizio (con tutto fermo: nessuno puo' sovrascriverla)
#   4. avvio del SOLO servizio; attesa che il processo "--server" di SYSTEM
#      sia in ascolto sulla pipe IPC e che nessun rustdesk.exe utente sia vivo
#   5. lettura ID e impostazione password anche via "rustdesk.exe --password"
#      (il servizio risponde "Done!" solo se l'ha accettata) e VERIFICA sul
#      file del servizio che la password sia stata registrata
#   6. registrazione nel pannello E-DA (nome, ID, password)
#
# Perche' tutto questo: "rustdesk.exe --password" parla via pipe con il
# processo che in quel momento la possiede. Se il servizio non e' ancora in
# ascolto, la finestra/tray di RustDesk dell'utente diventa lei stessa il
# server: la password finisce nel profilo utente, il comando dice "Done!" ma
# il servizio (quello che accetta le connessioni) non la vede mai.
# Da qui i fallimenti casuali della vecchia versione dello script.

# ===================== Parametri E-DA =====================
$Server          = 'rustdesk.eda.it'
$Key             = 'Z6bDmiCUSeI6T5HdF0+pfbDQEaU03lTN1PKA6eCIVTc='
$RegToken        = 'TOKEN_SEGRETO_EDA_RUSTDESK'
$RegUrl          = 'https://rustdesk.eda.it/api/register'
$FallbackVersion = '1.4.9'
$PresetPassword  = '007,Edasrl'   # password permanente fissa E-DA, usata SENZA chiedere; vuota = la chiede (invio = casuale)
$PasswordLength  = 12    # lunghezza della password generata a caso
# ==========================================================

$SvcName    = 'RustDesk'
$SvcCfgDir  = 'C:\Windows\ServiceProfiles\LocalService\AppData\Roaming\RustDesk\config'
$UserCfgDir = Join-Path $env:APPDATA 'RustDesk\config'
$SystemSid  = 'S-1-5-18'

$ErrorActionPreference = 'Continue'
$ProgressPreference    = 'SilentlyContinue'
try { [Console]::OutputEncoding = [Text.Encoding]::UTF8 } catch {}

# ----------------------- output -----------------------
function Write-Step([string]$m) { Write-Host ("  " + $m) -ForegroundColor Cyan }
function Write-Info([string]$m) { Write-Host ("     " + $m) }
function Write-Ok  ([string]$m) { Write-Host ("     OK  " + $m) -ForegroundColor Green }
function Write-Warn([string]$m) { Write-Host ("     !!  " + $m) -ForegroundColor Yellow }
function Write-Bad ([string]$m) { Write-Host ("     XX  " + $m) -ForegroundColor Red }
function Fail([string]$m, [int]$code = 1) {
    Write-Host ''
    Write-Host ("  ERRORE: " + $m) -ForegroundColor Red
    Write-Host ''
    exit $code
}

# ----------------------- file helpers -----------------------
function Write-TextNoBom([string]$Path, [string]$Text) {
    $dir = Split-Path -Parent $Path
    if (-not (Test-Path -LiteralPath $dir)) { New-Item -ItemType Directory -Path $dir -Force | Out-Null }
    [IO.File]::WriteAllText($Path, $Text, (New-Object Text.UTF8Encoding($false)))
}

# Valore stringa TOML: 'letterale' se possibile, altrimenti "con escape".
function ConvertTo-TomlString([string]$s) {
    if ($s -notmatch "['\x00-\x1F]") { return "'" + $s + "'" }
    return '"' + ($s -replace '\\', '\\' -replace '"', '\"') + '"'
}

# Legge una chiave della sezione radice di un file TOML (prima di ogni [tabella]).
function Get-TomlRootValue([string]$Path, [string]$Key) {
    if (-not (Test-Path -LiteralPath $Path)) { return $null }
    $lines = [IO.File]::ReadAllText($Path) -split "`r?`n"
    foreach ($l in $lines) {
        if ($l -match '^\s*\[\[?[^\]]*\]\]?\s*$') { break }     # inizio prima tabella: fine radice
        if ($l -match ('^\s*' + [regex]::Escape($Key) + '\s*=\s*(.*)$')) {
            $v = $Matches[1].Trim()
            if ($v -match "^'(.*)'\s*$") { return $Matches[1] }
            if ($v -match '^"(.*)"\s*$') { return ($Matches[1] -replace '\\"', '"' -replace '\\\\', '\') }
            return $v
        }
    }
    return $null
}

# Imposta (sostituisce o inserisce) una chiave nella sezione radice di un file
# TOML lasciando intatto tutto il resto (enc_id, key_pair, tabelle...).
# NB: le righe "    [" dentro key_pair NON sono intestazioni di tabella.
function Set-TomlRootValue([string]$Path, [string]$Key, [string]$TomlValue) {
    $lines = @()
    if (Test-Path -LiteralPath $Path) {
        $raw = [IO.File]::ReadAllText($Path)
        if ($raw.Length -gt 0) { $lines = $raw -split "`r?`n" }
    }
    $out = New-Object System.Collections.Generic.List[string]
    $inRoot = $true
    $done   = $false
    $keyRx  = '^\s*' + [regex]::Escape($Key) + '\s*='
    foreach ($l in $lines) {
        if ($inRoot -and ($l -match '^\s*\[\[?[^\]]*\]\]?\s*$')) { $inRoot = $false }   # prima tabella: fine radice
        if ($inRoot -and (-not $done) -and ($l -match $keyRx)) {
            $out.Add("$Key = $TomlValue"); $done = $true; continue
        }
        $out.Add($l)
    }
    # Chiave assente nella radice: la si mette in testa al file (sempre valido).
    if (-not $done) { $out.Insert(0, "$Key = $TomlValue") }
    $text = (($out -join "`n").TrimEnd("`n", "`r")) + "`n"
    Write-TextNoBom $Path $text
}

function Get-RustDesk2Toml {
    return @"
rendezvous_server = '$Server'
nat_type = 1
serial = 0

[options]
custom-rendezvous-server = '$Server'
key = '$Key'
api-server = ''
verification-method = 'use-both-passwords'
approve-mode = 'password'
"@
}

# ----------------------- processi / servizio -----------------------
function Get-RdProcs {
    $list = @()
    try {
        $procs = @(Get-CimInstance Win32_Process -Filter "Name='rustdesk.exe'" -ErrorAction Stop)
        foreach ($p in $procs) {
            $sid = ''
            try { $sid = [string](Invoke-CimMethod -InputObject $p -MethodName GetOwnerSid -ErrorAction Stop).Sid } catch {}
            $list += [pscustomobject]@{
                Pid      = [int]$p.ProcessId
                Cmd      = [string]$p.CommandLine
                Sid      = $sid
                IsSystem = ($sid -eq $SystemSid)
            }
        }
    } catch {}
    return ,$list
}

function Stop-AllRustDesk {
    $svc = Get-Service -Name $SvcName -ErrorAction SilentlyContinue
    if ($svc -and $svc.Status -ne 'Stopped') {
        try { Stop-Service -Name $SvcName -Force -ErrorAction Stop } catch {}
        try { $svc.WaitForStatus('Stopped', [TimeSpan]::FromSeconds(20)) } catch {}
    }
    for ($i = 0; $i -lt 12; $i++) {
        $procs = Get-RdProcs
        if ($procs.Count -eq 0) { return $true }
        & taskkill.exe /F /IM rustdesk.exe 2>&1 | Out-Null
        Start-Sleep -Seconds 1
    }
    return ((Get-RdProcs).Count -eq 0)
}

function Start-RdService {
    for ($i = 0; $i -lt 6; $i++) {
        try { Start-Service -Name $SvcName -ErrorAction Stop } catch {}
        $svc = Get-Service -Name $SvcName -ErrorAction SilentlyContinue
        if ($svc -and $svc.Status -eq 'Running') { return $true }
        Start-Sleep -Seconds 2
    }
    return $false
}

function Test-IpcPipe {
    try {
        $pipes = [IO.Directory]::GetFiles('\\.\pipe\')
        foreach ($p in $pipes) { if ($p -match '(?i)\\RustDesk\\query$') { return $true } }
        return $false
    } catch { return $null }   # elenco non disponibile: non e' un indizio
}

# Vero solo quando la pipe IPC puo' appartenere SOLO al processo --server di
# SYSTEM: c'e' il --server di SYSTEM, nessun rustdesk.exe di altri utenti
# (quelli trovati vengono chiusi) e, se verificabile, la pipe esiste.
function Test-DaemonReady {
    $procs   = Get-RdProcs
    $foreign = @($procs | Where-Object { -not $_.IsSystem })
    foreach ($f in $foreign) { & taskkill.exe /F /PID $f.Pid 2>&1 | Out-Null }
    if ($foreign.Count -gt 0) { return $false }
    $server = @($procs | Where-Object { $_.IsSystem -and $_.Cmd -match '--server' })
    if ($server.Count -eq 0) { return $false }
    $svc = Get-Service -Name $SvcName -ErrorAction SilentlyContinue
    if (-not $svc -or $svc.Status -ne 'Running') { return $false }
    $pipe = Test-IpcPipe
    if ($pipe -eq $false) { return $false }
    return $true
}

function Wait-DaemonReady([int]$TimeoutSec) {
    $deadline = (Get-Date).AddSeconds($TimeoutSec)
    while ((Get-Date) -lt $deadline) {
        if (Test-DaemonReady) { return $true }
        Start-Sleep -Milliseconds 800
    }
    return (Test-DaemonReady)
}

# ----------------------- esecuzione rustdesk.exe -----------------------
function Get-QuotedArg([string]$a) {
    if ($a -match '^[A-Za-z0-9_\-\.:/=@,+]+$') { return $a }
    $a = $a -replace '(\\*)"', '$1$1\"'
    $a = $a -replace '(\\+)$', '$1$1'
    return '"' + $a + '"'
}

# Esegue rustdesk.exe con gli argomenti dati e restituisce stdout+stderr.
function Invoke-RdCli([string]$Exe, [string[]]$Argv, [int]$TimeoutSec = 30) {
    $psi = New-Object System.Diagnostics.ProcessStartInfo
    $psi.FileName  = $Exe
    $psi.Arguments = (($Argv | ForEach-Object { Get-QuotedArg $_ }) -join ' ')
    $psi.UseShellExecute        = $false
    $psi.RedirectStandardOutput = $true
    $psi.RedirectStandardError  = $true
    $psi.CreateNoWindow         = $true
    try {
        $p = [System.Diagnostics.Process]::Start($psi)
        $so = $p.StandardOutput.ReadToEndAsync()
        $se = $p.StandardError.ReadToEndAsync()
        if (-not $p.WaitForExit($TimeoutSec * 1000)) {
            try { $p.Kill() } catch {}
            return '<<TIMEOUT>>'
        }
        return (($so.Result + "`n" + $se.Result).Trim())
    } catch {
        return ('<<ERRORE>> ' + $_.Exception.Message)
    }
}

function Find-RdExe {
    $cands = @()
    if ($env:ProgramFiles)        { $cands += (Join-Path $env:ProgramFiles 'RustDesk\rustdesk.exe') }
    if (${env:ProgramFiles(x86)}) { $cands += (Join-Path ${env:ProgramFiles(x86)} 'RustDesk\rustdesk.exe') }
    if ($env:LOCALAPPDATA)        { $cands += (Join-Path $env:LOCALAPPDATA 'Programs\RustDesk\rustdesk.exe') }
    foreach ($c in $cands) { if (Test-Path -LiteralPath $c) { return $c } }
    return $null
}

function New-RandomPassword([int]$Len) {
    $chars = 'ABCDEFGHJKLMNPQRSTUVWXYZabcdefghjkmnpqrstuvwxyz23456789'
    $sb = New-Object Text.StringBuilder
    for ($i = 0; $i -lt $Len; $i++) { [void]$sb.Append($chars[(Get-Random -Maximum $chars.Length)]) }
    return $sb.ToString()
}

# ----------------------- download -----------------------
function Resolve-DownloadUrl([string]$Pattern, [string]$Suffix) {
    # 1) API GitHub (nome esatto dell'asset)
    try {
        $r = Invoke-RestMethod 'https://api.github.com/repos/rustdesk/rustdesk/releases/latest' -TimeoutSec 20 -UseBasicParsing
        $a = @($r.assets | Where-Object { $_.name -like $Pattern }) | Select-Object -First 1
        if ($a) { return @{ Url = [string]$a.browser_download_url; Name = [string]$a.name } }
    } catch { Write-Info ('API GitHub non raggiungibile (' + $_.Exception.Message + ')') }
    # 2) redirect di /releases/latest -> tag dell'ultima versione (niente limiti API)
    $tag = $null
    try {
        $req = [Net.HttpWebRequest]::Create('https://github.com/rustdesk/rustdesk/releases/latest')
        $req.AllowAutoRedirect = $false
        $req.Timeout = 20000
        $req.UserAgent = 'eda-rustdesk-installer'
        $resp = $req.GetResponse()
        $loc = [string]$resp.Headers['Location']
        $resp.Close()
        if ($loc -and $loc -match '/tag/([0-9][0-9\.]*)$') { $tag = $Matches[1] }
    } catch {}
    if (-not $tag) { $tag = $FallbackVersion; Write-Info ('Uso la versione di riserva ' + $tag) }
    $name = 'rustdesk-' + $tag + '-' + $Suffix
    return @{ Url = ('https://github.com/rustdesk/rustdesk/releases/download/' + $tag + '/' + $name); Name = $name }
}

# =====================================================================
#                              FLUSSO
# =====================================================================
if ($env:EDA_RD_SELFTEST -eq '1') { return }   # usato solo per i test delle funzioni

Write-Host ''
Write-Host '  ================================================' -ForegroundColor White
Write-Host '    E-DA Srl - Installazione RustDesk' -ForegroundColor White
Write-Host '  ================================================' -ForegroundColor White
Write-Host ''

# --- Controllo sistema ---
if ([Environment]::OSVersion.Version.Major -lt 10) {
    Write-Host "  Questo computer NON e' Windows 10/11." -ForegroundColor Red
    Write-Host '  Per Windows 7/8/8.1 usa lo script dedicato: install-rustdesk-win7.bat'
    exit 1
}
$id = [Security.Principal.WindowsIdentity]::GetCurrent()
if (-not (New-Object Security.Principal.WindowsPrincipal($id)).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
    Fail 'servono i privilegi di amministratore.'
}

# --- 0. Nome e password ---
$RegName = Read-Host ('  Nome con cui registrare il client [invio = ' + $env:COMPUTERNAME + ']')
$RegName = ([string]$RegName).Trim()
if (-not $RegName) { $RegName = $env:COMPUTERNAME }

if ($PresetPassword) {
    # Password fissa E-DA: non viene chiesta e a video non viene mostrata in chiaro
    # (lo script gira sui PC dei clienti).
    $Password      = $PresetPassword
    $PasswordShown = '(predefinita E-DA)'
} else {
    $Password = Read-Host '  Password permanente [invio = genera casuale]'
    $Password = ([string]$Password).Trim()
    if (-not $Password) {
        $Password = New-RandomPassword $PasswordLength
        Write-Info ('Password generata: ' + $Password)
    } elseif ($Password.Length -lt 6) {
        Fail 'la password deve avere almeno 6 caratteri.'
    }
    $PasswordShown = $Password
}
Write-Host ''
Write-Host ('  Nome client : ' + $RegName)
Write-Host ('  Password    : ' + $PasswordShown)
Write-Host ''

# --- Gia' installato? (seconda esecuzione: cambio password, nuovo nome, riprova) ---
$RdExe = Find-RdExe
$doInstall = $true
if ($RdExe -and (Get-Service -Name $SvcName -ErrorAction SilentlyContinue)) {
    $ver = ''
    try { $ver = [string](Get-Item -LiteralPath $RdExe).VersionInfo.FileVersion } catch {}
    Write-Host ("  RustDesk risulta gia' installato" + $(if ($ver) { ' (versione ' + $ver + ')' } else { '' }) + ' e il servizio esiste.')
    $ans = Read-Host '  Scaricare e reinstallare/aggiornare comunque? [s/N]'
    if (([string]$ans).Trim() -notmatch '^[sS]') { $doInstall = $false }
    Write-Host ''
}

if ($doInstall) {
    # --- 1. Download ---
    Write-Step '[1/6] Download RustDesk...'
    try { [Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12 } catch {}
    try { [Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor 12288 } catch {}   # Tls13 se disponibile
    if ([Environment]::Is64BitOperatingSystem) { $pat = 'rustdesk-*x86_64.exe';     $suf = 'x86_64.exe' }
    else                                        { $pat = 'rustdesk-*x86-sciter.exe'; $suf = 'x86-sciter.exe' }
    $dl = Resolve-DownloadUrl $pat $suf
    Write-Info ('Versione : ' + $dl.Name)
    Write-Info ('Da       : ' + $dl.Url)
    $Setup = Join-Path $env:TEMP 'rustdesk-eda.exe'
    Remove-Item -LiteralPath $Setup -Force -ErrorAction SilentlyContinue
    $downloaded = $false
    for ($try = 1; $try -le 3 -and -not $downloaded; $try++) {
        try {
            Invoke-WebRequest -Uri $dl.Url -OutFile $Setup -UseBasicParsing -TimeoutSec 600
            $len = (Get-Item -LiteralPath $Setup).Length
            if ($len -gt 5MB) { $downloaded = $true } else { Write-Warn ('file troppo piccolo (' + $len + ' byte), riprovo...') }
        } catch { Write-Warn ('download fallito (tentativo ' + $try + '): ' + $_.Exception.Message) ; Start-Sleep -Seconds 3 }
    }
    if (-not $downloaded) { Fail 'download non riuscito. Verificare la connessione Internet.' }
    Write-Ok ('scaricato (' + [math]::Round((Get-Item -LiteralPath $Setup).Length / 1MB, 1) + ' MB)')

    # --- 2. Installazione ---
    Write-Step '[2/6] Installazione (attendere)...'
    # Configurazione E-DA nel profilo dell'utente PRIMA dell'installazione: cosi'
    # l'installer (che legge le opzioni dell'utente corrente) non trova opzioni
    # vecchie tipo stop-service e crea regolarmente il servizio.
    Write-TextNoBom (Join-Path $UserCfgDir 'RustDesk2.toml') (Get-RustDesk2Toml)
    # Chiude eventuali istanze precedenti (aggiornamento / seconda esecuzione).
    [void](Stop-AllRustDesk)
    # ATTENZIONE: NON usare "Start-Process -Wait": in Windows PowerShell aspetta anche
    # tutti i processi figli e l'installer lascia in esecuzione "rustdesk.exe --tray",
    # quindi lo script resterebbe fermo per sempre. Si aspetta SOLO l'installer.
    try {
        $psi = New-Object System.Diagnostics.ProcessStartInfo
        $psi.FileName        = $Setup
        $psi.Arguments       = '--silent-install'
        $psi.UseShellExecute = $false
        $ip = [System.Diagnostics.Process]::Start($psi)
        if ($ip.WaitForExit(15 * 60 * 1000)) { Write-Info ('installer terminato (codice ' + $ip.ExitCode + ')') }
        else { Write-Warn 'installer ancora in esecuzione dopo 15 minuti: proseguo comunque.' }
    } catch { Fail ('avvio installer fallito: ' + $_.Exception.Message) }
    $RdExe = $null
    $deadline = (Get-Date).AddSeconds(90)
    while ((Get-Date) -lt $deadline) {
        $RdExe = Find-RdExe
        $svc = Get-Service -Name $SvcName -ErrorAction SilentlyContinue
        if ($RdExe -and $svc) { break }
        Start-Sleep -Seconds 2
    }
    Remove-Item -LiteralPath $Setup -Force -ErrorAction SilentlyContinue
    if (-not $RdExe) { Fail 'rustdesk.exe non trovato dopo l''installazione.' }
    if (-not (Get-Service -Name $SvcName -ErrorAction SilentlyContinue)) { Fail 'il servizio RustDesk non e'' stato creato dall''installer.' }
    Write-Ok ('installato: ' + $RdExe)
} else {
    Write-Step '[1/6] Download RustDesk: saltato (gia'' installato)'
    Write-Step '[2/6] Installazione: saltata'
}

# --- 3. Configurazione con tutto fermo ---
Write-Step '[3/6] Configurazione server E-DA e password permanente...'
if (-not (Stop-AllRustDesk)) { Write-Warn 'alcuni processi rustdesk.exe non si sono chiusi, continuo comunque.' }
Write-TextNoBom (Join-Path $UserCfgDir 'RustDesk2.toml') (Get-RustDesk2Toml)
Write-TextNoBom (Join-Path $SvcCfgDir  'RustDesk2.toml') (Get-RustDesk2Toml)
$SvcToml = Join-Path $SvcCfgDir 'RustDesk.toml'
try {
    Set-TomlRootValue $SvcToml 'password' (ConvertTo-TomlString $Password)
    Write-Ok 'password scritta nella configurazione del servizio'
} catch { Write-Warn ('scrittura password nel file del servizio fallita: ' + $_.Exception.Message) }
Write-Ok ('server configurato: ' + $Server)

# --- 4. Avvio servizio e attesa del processo --server di SYSTEM ---
Write-Step '[4/6] Avvio servizio RustDesk...'
if (-not (Start-RdService)) { Fail 'il servizio RustDesk non parte.' 3 }
$ready = Wait-DaemonReady 60
if ($ready) { Write-Ok 'servizio in ascolto (processo --server di SYSTEM, nessuna istanza utente attiva)' }
else        { Write-Warn 'il servizio non risulta pronto entro 60 s: provo comunque a proseguire.' }

# --- 5. ID e password via IPC, con verifica ---
Write-Step '[5/6] Lettura ID e impostazione password permanente...'
$RdId = ''
for ($try = 1; $try -le 12 -and -not $RdId; $try++) {
    $out = Invoke-RdCli $RdExe @('--get-id') 20
    $cand = ($out -split "`r?`n" | ForEach-Object { $_.Trim() } | Where-Object { $_ -match '^[A-Za-z0-9_\-]{4,32}$' } | Select-Object -First 1)
    if ($cand) { $RdId = [string]$cand } else { Start-Sleep -Seconds 3 }
}
if ($RdId) { Write-Ok ('ID RustDesk: ' + $RdId) } else { Write-Bad 'ID non disponibile.' }

$ipcOk   = $false
$lastOut = ''
for ($try = 1; $try -le 10 -and -not $ipcOk; $try++) {
    if (-not (Test-DaemonReady)) { Start-Sleep -Seconds 3; continue }
    $lastOut = Invoke-RdCli $RdExe @('--password', $Password) 20
    if ($lastOut -match 'Done!') { $ipcOk = $true } else { Start-Sleep -Seconds 3 }
}
if ($ipcOk) { Write-Ok 'il servizio ha accettato la password (Done!)' }
else        { Write-Warn ('"rustdesk.exe --password" non confermato. Ultima risposta: ' + $lastOut) }

# Verifica sul file del servizio: dopo "Done!" il daemon salva la password in
# forma hash/cifrata (non piu' in chiaro). Se e' rimasta in chiaro il servizio
# la usa comunque (formato legacy), ma non ha confermato di averla ricevuta.
$stored = Get-TomlRootValue $SvcToml 'password'
$svcNow = Get-Service -Name $SvcName -ErrorAction SilentlyContinue
$pwStatus = ''
$pwCode   = 0
if (-not $svcNow -or $svcNow.Status -ne 'Running') {
    $pwStatus = 'NON VERIFICABILE: il servizio RustDesk non e'' in esecuzione'
    $pwCode = 3
} elseif ([string]::IsNullOrEmpty($stored)) {
    $pwStatus = 'NON IMPOSTATA (nessuna password nella configurazione del servizio)'
    $pwCode = 2
} elseif ($stored -eq $Password) {
    if ($ipcOk) { $pwStatus = 'impostata (file), ma il servizio non l''ha ancora convertita: riprovare la connessione tra qualche secondo' }
    else        { $pwStatus = 'impostata solo via file (il servizio non ha confermato via IPC): dovrebbe funzionare, verificare con una connessione di prova' }
} else {
    if ($ipcOk) { $pwStatus = 'VERIFICATA: accettata dal servizio e salvata in forma protetta' }
    else        { $pwStatus = 'salvata in forma protetta dal servizio (senza conferma IPC): verificare con una connessione di prova' }
}
if ($pwCode -eq 0) { Write-Ok ('password permanente: ' + $pwStatus) } else { Write-Bad ('password permanente: ' + $pwStatus) }

# --- 6. Registrazione nel pannello ---
Write-Step '[6/6] Registrazione nel pannello E-DA...'
$regStatus = 'saltata (ID non disponibile)'
if ($RdId) {
    $bodyObj = @{ name = $RegName; rustDeskId = $RdId; password = $Password }
    $body = [Text.Encoding]::UTF8.GetBytes((ConvertTo-Json $bodyObj -Compress))
    for ($try = 1; $try -le 3; $try++) {
        try {
            $r = Invoke-RestMethod -Uri $RegUrl -Method Post -Headers @{ 'X-Register-Token' = $RegToken } -ContentType 'application/json; charset=utf-8' -Body $body -TimeoutSec 30
            if ($r -and $r.updated) { $regStatus = 'OK (record esistente aggiornato)' } else { $regStatus = 'OK (nuovo record)' }
            break
        } catch {
            $regStatus = 'FALLITA: ' + $_.Exception.Message
            if ($try -lt 3) { Start-Sleep -Seconds 5 }
        }
    }
}
if ($regStatus -like 'OK*') { Write-Ok $regStatus } else { Write-Warn ('registrazione ' + $regStatus) }

# Tray per l'utente (l'installer l'aveva avviata, l'abbiamo chiusa al passo 3).
try { Start-Process -FilePath $RdExe -ArgumentList '--tray' -WindowStyle Hidden | Out-Null } catch {}

# --- Riepilogo ---
Write-Host ''
Write-Host '  ================================================' -ForegroundColor White
if ($pwCode -eq 0) { Write-Host '    Installazione completata' -ForegroundColor Green }
else               { Write-Host '    Installazione completata CON PROBLEMI' -ForegroundColor Red }
Write-Host '  ================================================' -ForegroundColor White
Write-Host ('  Nome client : ' + $RegName)
Write-Host ('  ID RustDesk : ' + $(if ($RdId) { $RdId } else { 'n/d' }))
Write-Host ('  Password    : ' + $PasswordShown)
Write-Host ('  Server      : ' + $Server)
Write-Host ('  Password permanente : ' + $pwStatus)
Write-Host ('  Registrazione        : ' + $regStatus)
Write-Host ''
if ($pwCode -ne 0) { exit $pwCode }
if (-not $RdId)    { exit 4 }
exit 0
