<#
.SYNOPSIS
    Registers the OtOpcUaFocasHost Windows service. Optional companion to
    Install-Services.ps1 — only run this on nodes where FOCAS driver instances will run
    with Tier-C process isolation enabled.

.DESCRIPTION
    FOCAS PR #220 / Tier-C isolation plan. Wraps OtOpcUa.Driver.FOCAS.Host.exe (net48 x86)
    as a Windows service using NSSM, running under the same service account as the main
    OtOpcUa service so the named-pipe ACL works. Passes the per-process shared secret via
    environment variable at service-start time so it never hits disk.

.PARAMETER InstallRoot
    Where the FOCAS Host binaries live (typically
    C:\Program Files\OtOpcUa\Driver.FOCAS.Host).

.PARAMETER ServiceAccount
    Service account SID or DOMAIN\name. Must match the main OtOpcUa server account so the
    PipeAcl match succeeds.

.PARAMETER FocasSharedSecret
    Per-process secret passed via env var. Generated freshly per install if not supplied.

.PARAMETER FocasBackend
    Backend selector for the Host process. One of:
      fwlib32      (default — real Fanuc Fwlib32.dll integration; requires licensed DLL on PATH)
      fake         (in-memory; smoke-test mode)
      unconfigured (safe default returning structured errors; use until hardware is wired)

.PARAMETER FocasPipeName
    Pipe name the Host listens on. Default: OtOpcUaFocas.

.EXAMPLE
    .\Install-FocasHost.ps1 -InstallRoot 'C:\Program Files\OtOpcUa\Driver.FOCAS.Host' `
        -ServiceAccount 'OTOPCUA\svc-otopcua' -FocasBackend fwlib32
#>
[CmdletBinding()]
param(
    [Parameter(Mandatory)] [string]$InstallRoot,
    [Parameter(Mandatory)] [string]$ServiceAccount,
    [string]$FocasSharedSecret,
    [ValidateSet('fwlib32','fake','unconfigured')] [string]$FocasBackend = 'unconfigured',
    [string]$FocasPipeName = 'OtOpcUaFocas',
    [string]$ServiceName = 'OtOpcUaFocasHost',
    [string]$NssmPath = 'C:\Program Files\nssm\nssm.exe'
)

$ErrorActionPreference = 'Stop'

function Resolve-Sid {
    param([string]$Account)
    if ($Account -match '^S-\d-\d+') { return $Account }
    try {
        $nt = New-Object System.Security.Principal.NTAccount($Account)
        return $nt.Translate([System.Security.Principal.SecurityIdentifier]).Value
    } catch {
        throw "Could not resolve '$Account' to a SID. Pass an explicit SID or check the account name."
    }
}

if (-not (Test-Path $NssmPath)) {
    throw "nssm.exe not found at '$NssmPath'. Install NSSM or pass -NssmPath."
}

$hostExe = Join-Path $InstallRoot 'OtOpcUa.Driver.FOCAS.Host.exe'
if (-not (Test-Path $hostExe)) {
    throw "FOCAS Host binary not found at '$hostExe'. Publish the Driver.FOCAS.Host project first."
}

if (-not $FocasSharedSecret) {
    $FocasSharedSecret = [System.Guid]::NewGuid().ToString('N')
    Write-Host "Generated FocasSharedSecret — store it alongside the OtOpcUa service config."
}

$allowedSid = Resolve-Sid $ServiceAccount

# Idempotent install — remove + re-create if present.
$existing = Get-Service -Name $ServiceName -ErrorAction SilentlyContinue
if ($existing) {
    Write-Host "Removing existing '$ServiceName' service..."
    & $NssmPath stop $ServiceName confirm | Out-Null
    & $NssmPath remove $ServiceName confirm | Out-Null
}

& $NssmPath install $ServiceName $hostExe | Out-Null
& $NssmPath set $ServiceName DisplayName 'OT-OPC-UA FOCAS Host (Tier-C isolated Fwlib32)' | Out-Null
& $NssmPath set $ServiceName Description 'Out-of-process Fwlib32.dll host for OtOpcUa FOCAS driver. Crash-isolated from the main OPC UA server.' | Out-Null
& $NssmPath set $ServiceName ObjectName  $ServiceAccount | Out-Null
& $NssmPath set $ServiceName Start SERVICE_AUTO_START | Out-Null
& $NssmPath set $ServiceName AppStdout (Join-Path $env:ProgramData 'OtOpcUa\focas-host-stdout.log') | Out-Null
& $NssmPath set $ServiceName AppStderr (Join-Path $env:ProgramData 'OtOpcUa\focas-host-stderr.log') | Out-Null
& $NssmPath set $ServiceName AppRotateFiles 1 | Out-Null
& $NssmPath set $ServiceName AppRotateBytes 10485760 | Out-Null

& $NssmPath set $ServiceName AppEnvironmentExtra `
    "OTOPCUA_FOCAS_PIPE=$FocasPipeName" `
    "OTOPCUA_ALLOWED_SID=$allowedSid" `
    "OTOPCUA_FOCAS_SECRET=$FocasSharedSecret" `
    "OTOPCUA_FOCAS_BACKEND=$FocasBackend" | Out-Null

& $NssmPath set $ServiceName DependOnService OtOpcUa | Out-Null

Write-Host "Installed '$ServiceName' under '$ServiceAccount' (SID=$allowedSid)."
Write-Host "Pipe: \\.\pipe\$FocasPipeName    Backend: $FocasBackend"
Write-Host "Start the service with: Start-Service $ServiceName"
Write-Host ""
Write-Host "NOTE: the Fwlib32 backend requires the licensed Fwlib32.dll on PATH"
Write-Host "alongside the Host exe. See docs/v2/focas-deployment.md."
