# hook-health-monitor.ps1 -- Standalone health check for governance hooks.
#
# Run periodically to verify:
#   - All hook files exist and are readable
#   - Hook files haven't been tampered with (SHA-256 verification)
#   - Log directories are writable
#   - No hooks are missing from the configuration
#
# T-049: Hook health monitoring.
#
# Usage:
#   pwsh hook-health-monitor.ps1 [-ManifestFile path/to/manifest.json]
#
# @connexum/ai-governance

param(
    [string]$ManifestFile = ''
)

$ErrorActionPreference = 'Stop'

$hookDir = $PSScriptRoot
$logDir = if ($env:GOVERNANCE_LOG_DIR) { $env:GOVERNANCE_LOG_DIR } else { Join-Path $env:TEMP 'governance/logs' }
$errors = 0
$warnings = 0

New-Item -ItemType Directory -Path $logDir -Force | Out-Null

$timestamp = [DateTime]::UtcNow.ToString('yyyy-MM-ddTHH:mm:ssZ')
$reportFile = Join-Path $logDir "hook-health-$([DateTime]::UtcNow.ToString('yyyyMMdd')).jsonl"

function Write-Check {
    param([string]$Status, [string]$Check, [string]$Detail)

    $entry = @{ timestamp = $timestamp; status = $Status; check = $Check; detail = $Detail } | ConvertTo-Json -Compress
    Add-Content -Path $reportFile -Value $entry -ErrorAction SilentlyContinue

    switch ($Status) {
        'FAIL' {
            [Console]::Error.WriteLine("x FAIL: $Check -- $Detail")
            $script:errors++
        }
        'WARN' {
            [Console]::Error.WriteLine("! WARN: $Check -- $Detail")
            $script:warnings++
        }
        default {
            [Console]::Error.WriteLine("v PASS: $Check")
        }
    }
}

# --- 1. Check PowerShell version ---
if ($PSVersionTable.PSVersion.Major -ge 7) {
    Write-Check 'PASS' 'powershell:version' "PowerShell $($PSVersionTable.PSVersion)"
} else {
    Write-Check 'WARN' 'powershell:version' "PowerShell $($PSVersionTable.PSVersion) -- recommend 7+"
}

# --- 2. Check hook files exist ---
$expectedHooks = @(
    'governance-file-shield.ps1'
    'destructive-command-guard.ps1'
    'secret-leak-scanner.ps1'
    'hook-utils.ps1'
    'output-exfiltration-scanner.ps1'
    'hook-health-monitor.ps1'
)

foreach ($hook in $expectedHooks) {
    $hookPath = Join-Path $hookDir $hook

    if (-not (Test-Path $hookPath)) {
        Write-Check 'FAIL' "hook:exists:$hook" 'File not found'
        continue
    }

    # Check for valid PowerShell header
    $firstLine = Get-Content $hookPath -TotalCount 1
    if ($firstLine -notmatch '^#') {
        Write-Check 'WARN' "hook:header:$hook" "Non-standard header: $firstLine"
    }

    Write-Check 'PASS' "hook:exists:$hook" 'Present and readable'
}

# --- 3. SHA-256 integrity verification ---
if ($ManifestFile -and (Test-Path $ManifestFile)) {
    try {
        $manifestData = Get-Content $ManifestFile -Raw | ConvertFrom-Json
        foreach ($hookEntry in $manifestData.hooks) {
            $fullPath = Join-Path $hookDir $hookEntry.file
            if (Test-Path $fullPath) {
                $actualHash = (Get-FileHash -Path $fullPath -Algorithm SHA256).Hash.ToLower()
                if ($actualHash -eq $hookEntry.sha256) {
                    Write-Check 'PASS' "integrity:$($hookEntry.file)" 'Hash matches'
                } else {
                    Write-Check 'FAIL' "integrity:$($hookEntry.file)" "TAMPERED: expected=$($hookEntry.sha256) actual=$actualHash"
                }
            }
        }
    } catch {
        Write-Check 'WARN' 'integrity:manifest' "Could not parse manifest: $_"
    }
} else {
    Write-Check 'WARN' 'integrity:manifest' 'No manifest file provided (use -ManifestFile)'
}

# --- 4. Check log directories ---
$governanceAuditDir = if ($env:GOVERNANCE_AUDIT_DIR) { $env:GOVERNANCE_AUDIT_DIR } else { Join-Path $env:TEMP 'governance/audit' }

foreach ($dir in @($logDir, $governanceAuditDir)) {
    if (Test-Path $dir) {
        try {
            $testFile = Join-Path $dir '.write-test'
            Set-Content -Path $testFile -Value 'test' -ErrorAction Stop
            Remove-Item $testFile -ErrorAction SilentlyContinue
            Write-Check 'PASS' "dir:writable:$dir" 'Writable'
        } catch {
            Write-Check 'FAIL' "dir:writable:$dir" 'Not writable'
        }
    } else {
        Write-Check 'WARN' "dir:exists:$dir" 'Does not exist (will be created on first use)'
    }
}

# --- 5. Check disk space ---
try {
    $drive = (Get-Item $logDir -ErrorAction SilentlyContinue).PSDrive
    if ($drive) {
        $freeGB = [math]::Round($drive.Free / 1GB, 2)
        if ($freeGB -lt 0.1) {
            Write-Check 'WARN' 'disk:space' "Low disk space: ${freeGB}GB available"
        } else {
            Write-Check 'PASS' 'disk:space' "${freeGB}GB available"
        }
    }
} catch { }

# --- Summary ---
[Console]::Error.WriteLine('')
[Console]::Error.WriteLine("Hook Health Summary: $errors errors, $warnings warnings")

$summaryEntry = @{
    timestamp = $timestamp
    status = if ($errors -gt 0) { 'UNHEALTHY' } else { 'HEALTHY' }
    errors = $errors
    warnings = $warnings
} | ConvertTo-Json -Compress
Add-Content -Path $reportFile -Value $summaryEntry -ErrorAction SilentlyContinue

if ($errors -gt 0) { exit 1 }
exit 0
