<#
    orchestrate-init-password.ps1
    Phase-1 user-managed-container-password — manual / NATS-dispatched
    end-to-end driver. Run on a Windows endpoint (DESKTOP-I1KFRDN for first
    tests).

    Pipeline:
      1. Show LaboratoMDM.UI.User.exe --dialog password-prompt → capture pw.
      2. Run SecureContainer.exe init-password with the captured pw,
         the supplied officer pubkeys, k/n, optional --tpm-bind.
      3. Show recovery key via UI.User --dialog recovery-key-display.
      4. POST init-password JSON output to backend
         /appmanagement/workspaces/containers/<id>/init-password/.

    Usage (manual):
      .\orchestrate-init-password.ps1 `
          -ContainerId 42 `
          -ContainerPath 'C:\LabMDM\ws-7-cnt-15.lsc' `
          -SizeArg '10G' `
          -Algorithm 'MKV256' `
          -Label 'Personal' `
          -OfficersJsonPath 'C:\ProgramData\LaboratoMDM\officers-ws7.json' `
          -ShamirK 2 -ShamirN 3 `
          -TpmBind `
          -BackendUrl 'https://win.mdmlab.ru' `
          -AuthToken '<TRMM token>'

    Notes:
      * Logs every step to %ProgramData%\LaboratoMDM\logs\init-password-<ts>.log.
      * Writes the recovery key NOWHERE on disk; it is only shown to the user
        via the recovery-key-display dialog. The user is responsible for
        printing / saving to USB.
      * On any error, re-runs of this script are safe AS LONG AS the container
        file does not yet exist (init-password refuses to overwrite). For a
        fresh retry, delete the .lsc file first.
#>
[CmdletBinding()]
param(
    [Parameter(Mandatory)] [int]    $ContainerId,
    [Parameter(Mandatory)] [string] $ContainerPath,
    [Parameter(Mandatory)] [string] $SizeArg,
    [string] $Algorithm = 'MKV256',
    [string] $Label = '',
    [Parameter(Mandatory)] [string] $OfficersJsonPath,
    [Parameter(Mandatory)] [int]    $ShamirK,
    [Parameter(Mandatory)] [int]    $ShamirN,
    [switch] $TpmBind,
    [Parameter(Mandatory)] [string] $BackendUrl,
    [Parameter(Mandatory)] [string] $AuthToken,
    [string] $UiUserExe = 'C:\Program Files (x86)\LaboratoMDM Agent\UI.User\LaboratoMDM.UI.User.exe',
    [string] $SecureContainerExe = 'C:\Program Files\LaboratoMDM\SecureContainer.exe'
)

$ErrorActionPreference = 'Stop'
$ts = (Get-Date).ToString('yyyyMMdd-HHmmss')
$logDir = Join-Path $env:ProgramData 'LaboratoMDM\logs'
New-Item -ItemType Directory -Force -Path $logDir | Out-Null
$log = Join-Path $logDir "init-password-$ts.log"
Start-Transcript -Path $log -Append | Out-Null

function Write-Step($msg) { Write-Host "[orchestrate] $msg" }

try {
    if (-not (Test-Path $UiUserExe))         { throw "UI.User.exe not found: $UiUserExe" }
    if (-not (Test-Path $SecureContainerExe)) { throw "SC.exe not found: $SecureContainerExe" }
    if (-not (Test-Path $OfficersJsonPath))   { throw "officers JSON not found: $OfficersJsonPath" }

    # ---- 1. Password prompt ---- #
    Write-Step "Step 1: ask user for password (UI.User --dialog password-prompt)"
    $promptArgs = @(
        '--dialog', 'password-prompt',
        '--container-id', $ContainerId,
        '--label', $Label
    )
    $promptOut = & $UiUserExe @promptArgs 2>&1 | Out-String
    Write-Step "prompt stdout: $($promptOut.Trim())"
    $promptJson = $promptOut | ConvertFrom-Json
    if (-not $promptJson.ok) {
        throw "User cancelled password prompt: $($promptJson.reason)"
    }
    $userPassword = $promptJson.data.password
    if ([string]::IsNullOrWhiteSpace($userPassword)) {
        throw "Password prompt returned empty password."
    }

    # ---- 2. SC.exe init-password ---- #
    Write-Step "Step 2: SC.exe init-password (container=$ContainerPath, k=$ShamirK, n=$ShamirN, tpm=$TpmBind)"
    $scArgs = @(
        'init-password', '--json',
        '--path', $ContainerPath,
        '--size', $SizeArg,
        '--algorithm', $Algorithm,
        '--label', $Label,
        '--password', $userPassword,
        '--shamir-k', $ShamirK,
        '--shamir-n', $ShamirN,
        '--escrow-officers-file', $OfficersJsonPath
    )
    if ($TpmBind) { $scArgs += @('--tpm-bind') }

    $scOut = & $SecureContainerExe @scArgs 2>&1 | Out-String
    Write-Step "sc.exe stdout (head): $($scOut.Substring(0, [Math]::Min(200, $scOut.Length)))..."
    $scReply = $scOut | ConvertFrom-Json
    if (-not $scReply.ok) {
        throw "SC.exe init-password failed: $($scReply.error)"
    }
    $initData = $scReply.data
    Write-Step "init-password OK; recovery_key_fp=$($initData.recovery_key_fingerprint_hex), tpm_bound=$($initData.tpm.bound), escrow_shares=$($initData.escrow_shares.Count)"

    # ---- 3. Show recovery key ---- #
    Write-Step "Step 3: show recovery key to user (UI.User --dialog recovery-key-display)"
    $rkArgs = @(
        '--dialog', 'recovery-key-display',
        '--container-label', $Label,
        '--recovery-key-b64', $initData.recovery_key_b64,
        '--recovery-key-fingerprint-hex', $initData.recovery_key_fingerprint_hex
    )
    $rkOut = & $UiUserExe @rkArgs 2>&1 | Out-String
    $rkJson = $rkOut | ConvertFrom-Json
    if (-not ($rkJson.ok -and $rkJson.data.user_confirmed_saved)) {
        Write-Warning "User did NOT confirm the recovery key was saved. Aborting before POST."
        throw "Recovery-key save not confirmed."
    }

    # ---- 4. POST to backend ---- #
    Write-Step "Step 4: POST init-password results to backend"
    $body = @{
        user_password_fingerprint = ''  # advisory, may be empty
        tpm = $initData.tpm
        escrow_method = $initData.escrow_method
        escrow_shares = $initData.escrow_shares
    } | ConvertTo-Json -Depth 8 -Compress

    $headers = @{
        'Authorization' = "Token $AuthToken"
        'Content-Type'  = 'application/json'
    }
    $url = "$($BackendUrl.TrimEnd('/'))/appmanagement/workspaces/containers/$ContainerId/init-password/"
    Invoke-RestMethod -Uri $url -Method POST -Headers $headers -Body $body | Out-Null
    Write-Step "POST OK."

    Write-Step "DONE."
}
catch {
    Write-Error $_
    Write-Step "FAILED: $($_.Exception.Message)"
    exit 1
}
finally {
    # NEVER persist the password — clear the local variable explicitly.
    if ($userPassword) { Clear-Variable -Name userPassword -ErrorAction SilentlyContinue }
    Stop-Transcript | Out-Null
}
