VBAF.Center.Scheduler.ps1

#Requires -Version 5.1
<#
.SYNOPSIS
    VBAF-Center Phase 8 — Scheduling Engine
.DESCRIPTION
    Controls how often VBAF-Center checks customer signals
    and runs the full pipeline automatically.

    Functions:
      Start-VBAFCenterSchedule — start automatic checking
      Stop-VBAFCenterSchedule — stop automatic checking
      Invoke-VBAFCenterRun — run pipeline once manually
      Get-VBAFCenterRunHistory — show recent results
#>


$script:SchedulePath  = Join-Path $env:USERPROFILE "VBAFCenter\schedules"
$script:HistoryPath   = Join-Path $env:USERPROFILE "VBAFCenter\history"

function Initialize-VBAFCenterScheduleStore {
    if (-not (Test-Path $script:SchedulePath)) { New-Item -ItemType Directory -Path $script:SchedulePath -Force | Out-Null }
    if (-not (Test-Path $script:HistoryPath))  { New-Item -ItemType Directory -Path $script:HistoryPath  -Force | Out-Null }
}

# ============================================================
# INVOKE-VBAFCENTERRUN — run full pipeline once
# ============================================================
function Invoke-VBAFCenterRun {
    param(
        [Parameter(Mandatory)] [string] $CustomerID,
        [switch] $Silent
    )

    Initialize-VBAFCenterScheduleStore

    if (-not $Silent) {
        Write-Host ""
        Write-Host ("VBAF-Center Run: {0} — {1}" -f $CustomerID, (Get-Date).ToString("yyyy-MM-dd HH:mm:ss")) -ForegroundColor Cyan
        Write-Host ""
    }

    # Step 1 — Load schedule config
    $schedFile = Join-Path $script:SchedulePath "$CustomerID-schedule.json"
    if (-not (Test-Path $schedFile)) {
        Write-Host "No schedule found for: $CustomerID" -ForegroundColor Red
        Write-Host "Run Start-VBAFCenterOnboarding first." -ForegroundColor Yellow
        return $null
    }
    $sched = Get-Content $schedFile -Raw | ConvertFrom-Json

    # Step 2 — Acquire signals
    $sigPath = Join-Path $env:USERPROFILE "VBAFCenter\signals"
    $sigFiles = Get-ChildItem $sigPath -Filter "$CustomerID-*.json" -ErrorAction SilentlyContinue
    $rawSignals  = @()
    $signalNames = @()

    foreach ($sf in $sigFiles) {
        $sc = Get-Content $sf.FullName -Raw | ConvertFrom-Json
        [double] $range = $sc.RawMax - $sc.RawMin
        [double] $raw   = $sc.RawMin + (Get-Random -Minimum 0 -Maximum 100) / 100.0 * $range
        [double] $norm  = if ($range -gt 0) { ($raw - $sc.RawMin) / $range } else { 0.0 }
        $norm           = [Math]::Max(0.0, [Math]::Min(1.0, $norm))
        $rawSignals     += $norm
        $signalNames    += $sc.SignalName
    }

    # If no signals configured use simulated pair
    if ($rawSignals.Count -eq 0) {
        $rawSignals  = @([double](Get-Random -Minimum 0 -Maximum 100)/100.0, [double](Get-Random -Minimum 0 -Maximum 100)/100.0)
        $signalNames = @("Signal1","Signal2")
    }

    # Step 3 — Route to agent (rule-based)
    [double] $avg = 0.0
    foreach ($s in $rawSignals) { $avg += $s }
    $avg /= $rawSignals.Count

    $action = if      ($avg -lt 0.25) { 0 }
              elseif  ($avg -lt 0.50) { 1 }
              elseif  ($avg -lt 0.75) { 2 }
              else                    { 3 }

    # Step 4 — Interpret action
    $actFile = Join-Path $env:USERPROFILE "VBAFCenter\actions\$CustomerID-actions.txt"
    $actionName    = @("Monitor","Reassign","Reroute","Escalate")[$action]
    $actionCommand = @("No action needed","Reassign resource","Switch approach","Emergency response")[$action]

    if (Test-Path $actFile) {
        $lines = Get-Content $actFile
        foreach ($line in $lines) {
            $parts = $line -split "\|"
            if ([int]$parts[0] -eq $action) {
                $actionName    = $parts[1]
                $actionCommand = $parts[2]
                break
            }
        }
    }

    # Step 5 — Log result
    $result = @{
        CustomerID    = $CustomerID
        Timestamp     = (Get-Date).ToString("yyyy-MM-dd HH:mm:ss")
        Signals       = $rawSignals
        AvgSignal     = [Math]::Round($avg, 4)
        Action        = $action
        ActionName    = $actionName
        ActionCommand = $actionCommand
    }

    $histFile = Join-Path $script:HistoryPath "$CustomerID-$(Get-Date -Format 'yyyyMMdd_HHmmss').json"
    $result | ConvertTo-Json | Set-Content $histFile -Encoding UTF8

    # Step 6 — Display
    if (-not $Silent) {
        $sigStr = ($rawSignals | ForEach-Object { $_.ToString("F2") }) -join ", "
        $color  = if ($action -ge 3) { "Red" } elseif ($action -ge 2) { "Yellow" } else { "Green" }

        Write-Host (" Signals : [{0}]" -f $sigStr)       -ForegroundColor White
        Write-Host (" Avg level : {0:F2}" -f $avg)          -ForegroundColor White
        Write-Host (" Action : {0} — {1}" -f $action, $actionName) -ForegroundColor $color
        Write-Host (" Command : {0}" -f $actionCommand)   -ForegroundColor $color
        Write-Host ""
    }

    return $result
}

# ============================================================
# START-VBAFCENTERSCHEDULE — loop until stopped
# ============================================================
function Start-VBAFCenterSchedule {
    param(
        [Parameter(Mandatory)] [string] $CustomerID,
        [int] $MaxRuns = 0   # 0 = run forever until Ctrl+C
    )

    $schedFile = Join-Path $script:SchedulePath "$CustomerID-schedule.json"
    if (-not (Test-Path $schedFile)) {
        Write-Host "No schedule found for: $CustomerID" -ForegroundColor Red
        return
    }

    $sched = Get-Content $schedFile -Raw | ConvertFrom-Json
    [int] $intervalSec = $sched.IntervalMinutes * 60
    [int] $runCount    = 0

    Write-Host ""
    Write-Host "VBAF-Center Schedule Started" -ForegroundColor Cyan
    Write-Host (" Customer : {0}" -f $CustomerID)             -ForegroundColor White
    Write-Host (" Interval : every {0} minutes" -f $sched.IntervalMinutes) -ForegroundColor White
    Write-Host " Press Ctrl+C to stop." -ForegroundColor DarkGray
    Write-Host ""

    while ($true) {
        $runCount++
        Write-Host (" [{0}] Run #{1}" -f (Get-Date).ToString("HH:mm:ss"), $runCount) -ForegroundColor DarkGray

        $result = Invoke-VBAFCenterRun -CustomerID $CustomerID -Silent:$false

        if ($MaxRuns -gt 0 -and $runCount -ge $MaxRuns) {
            Write-Host "Max runs reached. Stopping." -ForegroundColor Yellow
            break
        }

        Write-Host (" Next run in {0} minutes..." -f $sched.IntervalMinutes) -ForegroundColor DarkGray
        Start-Sleep -Seconds $intervalSec
    }
}

# ============================================================
# GET-VBAFCENTERRUNHISTORY
# ============================================================
function Get-VBAFCenterRunHistory {
    param(
        [Parameter(Mandatory)] [string] $CustomerID,
        [int] $Last = 10
    )

    Initialize-VBAFCenterScheduleStore

    $files = Get-ChildItem $script:HistoryPath -Filter "$CustomerID-*.json" |
             Sort-Object LastWriteTime -Descending |
             Select-Object -First $Last

    if ($files.Count -eq 0) {
        Write-Host "No run history for: $CustomerID" -ForegroundColor Yellow
        return
    }

    Write-Host ""
    Write-Host "Run History: $CustomerID (last $($files.Count) runs)" -ForegroundColor Cyan
    Write-Host (" {0,-20} {1,-8} {2,-12} {3}" -f "Timestamp","Action","Name","Command") -ForegroundColor Yellow
    Write-Host (" {0}" -f ("-" * 75)) -ForegroundColor DarkGray

    foreach ($f in $files) {
        $r     = Get-Content $f.FullName -Raw | ConvertFrom-Json
        $color = if ($r.Action -ge 3) { "Red" } elseif ($r.Action -ge 2) { "Yellow" } else { "Green" }
        Write-Host (" {0,-20} {1,-8} {2,-12} {3}" -f $r.Timestamp, $r.Action, $r.ActionName, $r.ActionCommand) -ForegroundColor $color
    }
    Write-Host ""
}

Write-Host "VBAF-Center Phase 8 loaded [Scheduling Engine]"       -ForegroundColor Cyan
Write-Host " Invoke-VBAFCenterRun — run pipeline once"     -ForegroundColor White
Write-Host " Start-VBAFCenterSchedule — start auto-checking"   -ForegroundColor White
Write-Host " Get-VBAFCenterRunHistory — show recent results"   -ForegroundColor White
Write-Host ""