param(
    [string]$AppPackageName = "UnifiedImaging.ImageAnywhere",
    [string]$ProcessName = "IAUWP",
    [string]$AgentInstallDirectory = (Join-Path $env:LOCALAPPDATA "Programs\ImageAnywhereAgent"),
    [string]$AgentTaskName = "ImageAnywhereAgent",
    [switch]$RequireStartupTask,
    [switch]$RequireClinicalApplianceMode,
    [string]$ExpectedAppUserModelId = "UnifiedImaging.ImageAnywhere_ytf96cz97jc64!App",
    [ValidateRange(0, 600)]
    [int]$ClientHeartbeatWaitSeconds = 120,
    [string]$OutputJsonPath
)

Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"

if ([string]::IsNullOrWhiteSpace($OutputJsonPath)) {
    $OutputJsonPath = Join-Path $PSScriptRoot "field-verify-result.json"
}

function Get-TaskStatus {
    param([string]$TaskName)

    $previousErrorActionPreference = $ErrorActionPreference
    $ErrorActionPreference = "Continue"
    try {
        $output = & schtasks.exe /Query /TN $TaskName /FO LIST 2>&1
        $taskExitCode = $LASTEXITCODE
    }
    finally {
        $ErrorActionPreference = $previousErrorActionPreference
    }

    return [pscustomobject]@{
        Exists = ($taskExitCode -eq 0)
        Output = ($output | Out-String).Trim()
    }
}

function Get-ObjectPropertyValue {
    param(
        [object]$Target,
        [string]$Name
    )

    if (-not $Target) { return $null }
    $property = $Target.PSObject.Properties[$Name]
    if ($property) { return $property.Value }
    return $null
}

function Read-AgentStatus {
    param([string]$AgentExecutable)

    if (-not (Test-Path -LiteralPath $AgentExecutable)) { return $null }
    try {
        $statusText = (& $AgentExecutable --status-json | Out-String).Trim()
        $jsonStart = $statusText.IndexOf("{")
        if ($jsonStart -gt 0) {
            $statusText = $statusText.Substring($jsonStart)
        }
        if ([string]::IsNullOrWhiteSpace($statusText)) { return $null }
        return [pscustomobject]@{
            Text = $statusText
            Parsed = ($statusText | ConvertFrom-Json)
        }
    }
    catch {
        return $null
    }
}

$appPackage = Get-AppxPackage -Name $AppPackageName -ErrorAction SilentlyContinue
$appProcesses = @(Get-Process -Name $ProcessName -ErrorAction SilentlyContinue)
$agentExe = Join-Path $AgentInstallDirectory "agent\IAUWP.Agent.exe"
$pidPath = Join-Path $AgentInstallDirectory "run\agent.pid"
$agentPid = $null
$agentProcess = $null

# The pid file is a hint only: the sign-in task launch path never writes it, and pids
# get reused. A name+path process scan is the authoritative "running" signal.
if (Test-Path -LiteralPath $agentExe) {
    $agentProcess = Get-Process -Name IAUWP.Agent -ErrorAction SilentlyContinue |
        Where-Object {
            try {
                [string]::Equals($_.Path, $agentExe, [StringComparison]::OrdinalIgnoreCase)
            }
            catch {
                $false
            }
        } |
        Select-Object -First 1
    if ($agentProcess) {
        $agentPid = $agentProcess.Id
    }
}

if (-not $agentProcess -and (Test-Path -LiteralPath $pidPath)) {
    $pidText = Get-Content -LiteralPath $pidPath -Raw
    if ($pidText -match '^\s*\d+\s*$') {
        $recordedPid = [int]$pidText
        $recordedProcess = Get-Process -Id $recordedPid -ErrorAction SilentlyContinue
        if ($recordedProcess -and $recordedProcess.ProcessName -eq "IAUWP.Agent") {
            $agentProcess = $recordedProcess
            $agentPid = $recordedPid
        }
    }
}

$statusRead = Read-AgentStatus -AgentExecutable $agentExe
$agentStatusText = if ($statusRead) { $statusRead.Text } else { $null }
$agentStatus = if ($statusRead) { $statusRead.Parsed } else { $null }

if ($RequireClinicalApplianceMode.IsPresent -and $ClientHeartbeatWaitSeconds -gt 0) {
    $heartbeatDeadline = (Get-Date).AddSeconds($ClientHeartbeatWaitSeconds)
    while ((Get-Date) -lt $heartbeatDeadline) {
        $supervision = Get-ObjectPropertyValue -Target $agentStatus -Name "ClientSupervision"
        $clientSchema = Get-ObjectPropertyValue -Target $supervision -Name "ClientSchemaVersion"
        $heartbeatAge = Get-ObjectPropertyValue -Target $supervision -Name "HeartbeatAgeSeconds"
        $freshHeartbeatObserved = $false
        if ($null -ne $heartbeatAge) {
            try { $freshHeartbeatObserved = ([double]$heartbeatAge -le 90) } catch { }
        }
        if ([string]$clientSchema -eq "1" -and $freshHeartbeatObserved) {
            break
        }
        Start-Sleep -Seconds 2
        $statusRead = Read-AgentStatus -AgentExecutable $agentExe
        $agentStatusText = if ($statusRead) { $statusRead.Text } else { $null }
        $agentStatus = if ($statusRead) { $statusRead.Parsed } else { $null }
    }
}

$taskStatus = Get-TaskStatus -TaskName $AgentTaskName
$startupLauncherPath = Join-Path (Split-Path -Path $agentExe -Parent) "Start-AgentHidden.vbs"
$startupLauncherText = if (Test-Path -LiteralPath $startupLauncherPath) { Get-Content -LiteralPath $startupLauncherPath -Raw } else { $null }
$taskTargetsExpectedAgent = $taskStatus.Exists -and
    ($taskStatus.Output -match [regex]::Escape($startupLauncherPath)) -and
    (-not [string]::IsNullOrWhiteSpace($startupLauncherText)) -and
    ($startupLauncherText -match [regex]::Escape($agentExe))
$agentPaired = $false
if ($agentStatus -and $agentStatus.AuthStatus) {
    $agentPaired = [string]$agentStatus.AuthStatus -match '^auth=paired'
}

$agentSettingsPath = Join-Path $env:LOCALAPPDATA "ImageAnywhere\agent\agent-settings.json"
$agentSettings = $null
$agentSettingsParsed = $false
if (Test-Path -LiteralPath $agentSettingsPath) {
    try {
        $agentSettings = Get-Content -LiteralPath $agentSettingsPath -Raw | ConvertFrom-Json
        $agentSettingsParsed = ($null -ne $agentSettings)
    }
    catch { }
}
$configuredSupervision = Get-ObjectPropertyValue -Target $agentSettings -Name "ClientSupervision"
$configuredEnabledValue = Get-ObjectPropertyValue -Target $configuredSupervision -Name "Enabled"
$configuredEnabled = ($configuredEnabledValue -is [bool]) -and $configuredEnabledValue
$configuredMode = [string](Get-ObjectPropertyValue -Target $configuredSupervision -Name "Mode")
$configuredAumid = [string](Get-ObjectPropertyValue -Target $configuredSupervision -Name "AppUserModelId")
$supervisionStatus = Get-ObjectPropertyValue -Target $agentStatus -Name "ClientSupervision"
$clientSchemaVersion = [string](Get-ObjectPropertyValue -Target $supervisionStatus -Name "ClientSchemaVersion")
$heartbeatAgeSeconds = Get-ObjectPropertyValue -Target $supervisionStatus -Name "HeartbeatAgeSeconds"
$heartbeatFresh = $false
if ($null -ne $heartbeatAgeSeconds) {
    try { $heartbeatFresh = ([double]$heartbeatAgeSeconds -le 90) } catch { }
}
$aumidMatches = [string]::Equals($configuredAumid, $ExpectedAppUserModelId, [StringComparison]::Ordinal)
$clinicalModeReady = $agentSettingsParsed -and $configuredEnabled -and
    ($configuredMode -in @("Shadow", "Active")) -and $aumidMatches -and
    $taskTargetsExpectedAgent -and ([string]$clientSchemaVersion -eq "1") -and $heartbeatFresh
$clinicalReadinessReasons = New-Object System.Collections.Generic.List[string]
if (-not $agentSettingsParsed) { $clinicalReadinessReasons.Add("agent settings not readable") | Out-Null }
if (-not $configuredEnabled) { $clinicalReadinessReasons.Add("client supervision not enabled") | Out-Null }
if ($configuredMode -notin @("Shadow", "Active")) { $clinicalReadinessReasons.Add("client supervision mode not supported") | Out-Null }
if (-not $aumidMatches) { $clinicalReadinessReasons.Add("configured AUMID does not match") | Out-Null }
if (-not $taskTargetsExpectedAgent) { $clinicalReadinessReasons.Add("startup task does not target expected agent launcher") | Out-Null }
if ([string]$clientSchemaVersion -ne "1") { $clinicalReadinessReasons.Add("client heartbeat schema 1 not observed") | Out-Null }
if (-not $heartbeatFresh) { $clinicalReadinessReasons.Add("fresh client heartbeat not observed") | Out-Null }

$summary = [pscustomobject]@{
    SchemaVersion = 1
    CapturedAt = (Get-Date).ToString("O")
    Tool = "Verify-ImageAnywhereField"
    App = [pscustomobject]@{
        Installed = ($null -ne $appPackage)
        PackageFullName = if ($appPackage) { $appPackage.PackageFullName } else { $null }
        Version = if ($appPackage) { [string]$appPackage.Version } else { $null }
        RunningProcessCount = $appProcesses.Count
        Processes = @($appProcesses | Select-Object Id, Path, StartTime, Responding)
    }
    Agent = [pscustomobject]@{
        Installed = (Test-Path -LiteralPath $agentExe)
        InstallDirectory = $AgentInstallDirectory
        ExePath = $agentExe
        PidFile = if (Test-Path -LiteralPath $pidPath) { $pidPath } else { $null }
        Pid = $agentPid
        Running = ($null -ne $agentProcess)
        Paired = $agentPaired
        AuthStatus = if ($agentStatus) { $agentStatus.AuthStatus } else { $null }
        HeartbeatCount = if ($agentStatus) { $agentStatus.HeartbeatCount } else { $null }
        StatusJsonParsed = ($null -ne $agentStatus)
        StatusJson = $agentStatusText
    }
    StartupTask = [pscustomobject]@{
        TaskName = $AgentTaskName
        Exists = $taskStatus.Exists
        LauncherPath = $startupLauncherPath
        TargetsExpectedAgent = $taskTargetsExpectedAgent
        QueryOutput = $taskStatus.Output
    }
    ClinicalAppliance = [pscustomobject]@{
        Required = $RequireClinicalApplianceMode.IsPresent
        SettingsPath = $agentSettingsPath
        SettingsParsed = $agentSettingsParsed
        Enabled = $configuredEnabled
        Mode = $configuredMode
        ConfiguredAppUserModelId = $configuredAumid
        ExpectedAppUserModelId = $ExpectedAppUserModelId
        AppUserModelIdMatches = $aumidMatches
        ClientSchemaVersion = $clientSchemaVersion
        HeartbeatAgeSeconds = $heartbeatAgeSeconds
        HeartbeatFresh = $heartbeatFresh
        Ready = $clinicalModeReady
        ReadinessReasons = @($clinicalReadinessReasons.ToArray())
        RollbackCommand = "powershell.exe -NoProfile -ExecutionPolicy Bypass -File `"$PSScriptRoot\Rollback-ClinicalApplianceMode.ps1`""
    }
}

$summary | ConvertTo-Json -Depth 10 | Set-Content -Path $OutputJsonPath -Encoding UTF8

Write-Host ("ImageAnywhere app installed: {0}" -f $(if ($summary.App.Installed) { "OK" } else { "NO" }))
Write-Host ("ImageAnywhere app running: {0}" -f $summary.App.RunningProcessCount)
Write-Host ("Agent installed: {0}" -f $(if ($summary.Agent.Installed) { "OK" } else { "NO" }))
Write-Host ("Agent running: {0}" -f $(if ($summary.Agent.Running) { "OK" } else { "NO" }))
Write-Host ("Agent paired: {0}" -f $(if ($summary.Agent.Paired) { "OK" } else { "Needs sign-in + Pair agent" }))
Write-Host ("Agent startup task: {0}" -f $(if ($summary.StartupTask.Exists) { "OK" } else { "Not configured" }))
if ($RequireClinicalApplianceMode.IsPresent) {
    Write-Host ("Clinical appliance readiness: {0}" -f $(if ($summary.ClinicalAppliance.Ready) { "OK" } else { "Not ready" }))
}
Write-Host "Verification JSON: $OutputJsonPath"

$verdictReasons = New-Object System.Collections.Generic.List[string]
if (-not $summary.App.Installed) { $verdictReasons.Add("app not installed") | Out-Null }
if (-not $summary.Agent.Installed) { $verdictReasons.Add("agent not installed") | Out-Null }
if (-not $summary.Agent.Running) { $verdictReasons.Add("agent not running") | Out-Null }
if (-not $summary.Agent.StatusJsonParsed) { $verdictReasons.Add("agent status not readable") | Out-Null }
if ($RequireStartupTask.IsPresent -and -not $summary.StartupTask.Exists) { $verdictReasons.Add("sign-in startup task missing") | Out-Null }
if ($RequireClinicalApplianceMode.IsPresent -and -not $summary.ClinicalAppliance.Ready) {
    $verdictReasons.Add("clinical appliance not ready: " + ($summary.ClinicalAppliance.ReadinessReasons -join ", ")) | Out-Null
}

if (-not $summary.Agent.Paired) {
    Write-Host ""
    Write-Host "NOTE: the agent is NOT PAIRED yet. Always-on upload does not work until someone"
    Write-Host "signs in to ImageAnywhere on this machine and clicks 'Pair agent' in Connections."
}

Write-Host ""
if ($verdictReasons.Count -eq 0) {
    Write-Host "VERDICT: PASS"
    exit 0
}

Write-Host ("VERDICT: FAIL ({0})" -f ($verdictReasons -join "; "))
exit 1