VBAF.Center.TMSSimulator.ps1

#Requires -Version 5.1
<#
.SYNOPSIS
    VBAF-Center TMS Simulator - Real World Test Engine
.DESCRIPTION
    Simulates a Transport Management System feeding live data into VBAF-Center.
    2 signals. 3 events. 4 modes. Fully connected to VBAF-Center pipeline.
 
    Signals:
      Signal1 — Empty Driving %
      Signal2 — On-Time Delivery %
 
    Events:
      WeatherEvent — On-Time drops, Cost rises
      TrafficJam — ETA drops, Cost rises
      VehicleBreakdown — Fleet drops, Cost spikes
 
    Modes:
      Shadow — every 30 minutes (48 episodes/day)
      GoLive — every 10 minutes (144 episodes/day)
      Autonomy — every 5 minutes (288 episodes/day)
      RealTime — continuous demo/stress test
 
    Functions:
      Get-VBAFTMSSignal — get one signal value (time-aware)
      Get-VBAFTMSAllSignals — get both signals as snapshot
      Invoke-VBAFTMSEvent — fire a named or random event
      Show-VBAFTMSStatus — dashboard view of current state
      Invoke-VBAFTMSDayReplay — run full day compressed
      Start-VBAFTMSSchedule — run in chosen mode continuously
#>


# ============================================================
# STATE
# ============================================================
$script:TMSState = @{
    ActiveEvent       = $null
    EventRoundsLeft   = 0
    EmptyDrivingBase  = 32.0
    OnTimeBase        = 74.0
    LastSnapshot      = $null
}

# ============================================================
# TIME OF DAY CURVE
# Returns a multiplier 0.0 - 1.0 based on hour of day
# ============================================================
function Get-TMSTimeCurve {
    param([int]$Hour)
    switch ($Hour) {
        {$_ -lt 5}            { return 0.3 }   # Night — low activity
        {$_ -in 5..7}         { return 0.6 }   # Morning start
        {$_ -in 8..11}        { return 1.0 }   # Morning peak — best performance
        {$_ -in 12..14}       { return 0.9 }   # Midday plateau
        {$_ -in 15..17}       { return 0.8 }   # Afternoon pressure
        {$_ -in 18..20}       { return 0.6 }   # Evening wind-down
        {$_ -in 21..23}       { return 0.4 }   # Night shift
        default                { return 0.5 }
    }
}

# ============================================================
# DAY OF WEEK MODIFIER
# ============================================================
function Get-TMSDayModifier {
    $day = (Get-Date).DayOfWeek
    switch ($day) {
        "Monday"    { return @{ Empty=-5;  OnTime=-3  } }
        "Tuesday"   { return @{ Empty=-8;  OnTime=+5  } }
        "Wednesday" { return @{ Empty=0;   OnTime=0   } }
        "Thursday"  { return @{ Empty=+2;  OnTime=-2  } }
        "Friday"    { return @{ Empty=+8;  OnTime=-5  } }
        "Saturday"  { return @{ Empty=+15; OnTime=-8  } }
        "Sunday"    { return @{ Empty=+20; OnTime=-12 } }
        default     { return @{ Empty=0;   OnTime=0   } }
    }
}

# ============================================================
# GET-VBAFTMSSIGNAL
# ============================================================
function Get-VBAFTMSSignal {
    param(
        [Parameter(Mandatory)] [ValidateSet("EmptyDriving","OnTimeDelivery")]
        [string] $SignalName
    )

    $hour    = (Get-Date).Hour
    $curve   = Get-TMSTimeCurve -Hour $hour
    $dayMod  = Get-TMSDayModifier
    $noise   = (Get-Random -Minimum -50 -Maximum 50) / 10.0  # -5.0 to +5.0

    switch ($SignalName) {
        "EmptyDriving" {
            $base  = $script:TMSState.EmptyDrivingBase
            $value = $base + ($dayMod.Empty) + ((1.0 - $curve) * 20) + $noise

            # Event modifier
            if ($script:TMSState.ActiveEvent -eq "VehicleBreakdown") { $value += 15 }
            if ($script:TMSState.ActiveEvent -eq "TrafficJam")        { $value += 8  }
        }
        "OnTimeDelivery" {
            $base  = $script:TMSState.OnTimeBase
            $value = $base + ($dayMod.OnTime) + (($curve - 0.5) * 10) + $noise

            # Event modifier
            if ($script:TMSState.ActiveEvent -eq "WeatherEvent")      { $value -= 20 }
            if ($script:TMSState.ActiveEvent -eq "TrafficJam")        { $value -= 15 }
            if ($script:TMSState.ActiveEvent -eq "VehicleBreakdown")  { $value -= 10 }
        }
    }

    # Clamp to 0-100
    $value = [Math]::Round([Math]::Max(0, [Math]::Min(100, $value)), 1)
    return $value
}

# ============================================================
# GET-VBAFTMSALLSIGNALS
# ============================================================
function Get-VBAFTMSAllSignals {

    $empty  = Get-VBAFTMSSignal -SignalName "EmptyDriving"
    $ontime = Get-VBAFTMSSignal -SignalName "OnTimeDelivery"

    $snapshot = @{
        Timestamp       = (Get-Date).ToString("yyyy-MM-dd HH:mm:ss")
        EmptyDriving    = $empty
        OnTimeDelivery  = $ontime
        ActiveEvent     = if ($script:TMSState.ActiveEvent) { $script:TMSState.ActiveEvent } else { "None" }
    }

    $script:TMSState.LastSnapshot = $snapshot

    # Tick down event rounds
    if ($script:TMSState.EventRoundsLeft -gt 0) {
        $script:TMSState.EventRoundsLeft--
        if ($script:TMSState.EventRoundsLeft -eq 0) {
            Write-Host " [TMS] Event '$($script:TMSState.ActiveEvent)' has cleared." -ForegroundColor DarkGray
            $script:TMSState.ActiveEvent = $null
        }
    }

    return $snapshot
}

# ============================================================
# INVOKE-VBAFTMSEVENT
# ============================================================
function Invoke-VBAFTMSEvent {
    param(
        [ValidateSet("WeatherEvent","TrafficJam","VehicleBreakdown","Random")]
        [string] $Event = "Random",
        [int]    $Rounds = 3
    )

    if ($Event -eq "Random") {
        $events = @("WeatherEvent","TrafficJam","VehicleBreakdown")
        $Event  = $events[(Get-Random -Maximum 3)]
    }

    $script:TMSState.ActiveEvent     = $Event
    $script:TMSState.EventRoundsLeft = $Rounds

    $description = switch ($Event) {
        "WeatherEvent"     { "On-Time drops, route efficiency down" }
        "TrafficJam"       { "ETA accuracy drops, cost rises"       }
        "VehicleBreakdown" { "Fleet availability drops, cost spikes" }
    }

    Write-Host ""
    Write-Host " [TMS EVENT FIRED]" -ForegroundColor Red
    Write-Host (" Event : {0}" -f $Event)       -ForegroundColor Yellow
    Write-Host (" Effect : {0}" -f $description) -ForegroundColor Yellow
    Write-Host (" Rounds : {0}" -f $Rounds)      -ForegroundColor Yellow
    Write-Host ""
}

# ============================================================
# SHOW-VBAFTMSSTATUS
# ============================================================
function Show-VBAFTMSStatus {

    $s = Get-VBAFTMSAllSignals

    $emptyColor  = if ($s.EmptyDriving -gt 40)  { "Red"   } elseif ($s.EmptyDriving -gt 25)  { "Yellow" } else { "Green" }
    $ontimeColor = if ($s.OnTimeDelivery -lt 70) { "Red"   } elseif ($s.OnTimeDelivery -lt 85) { "Yellow" } else { "Green" }

    Write-Host ""
    Write-Host " +--------------------------------------+" -ForegroundColor Cyan
    Write-Host " — VBAF TMS Simulator — Status —" -ForegroundColor Cyan
    Write-Host " —--------------------------------------—" -ForegroundColor Cyan
    Write-Host (" — Time : {0,-27}—" -f $s.Timestamp)   -ForegroundColor White
    Write-Host (" — Event : {0,-27}—" -f $s.ActiveEvent) -ForegroundColor Yellow
    Write-Host " —--------------------------------------—" -ForegroundColor Cyan
    Write-Host (" — Empty Driving : {0,6} % —" -f $s.EmptyDriving)   -ForegroundColor $emptyColor
    Write-Host (" — On-Time Delivery : {0,6} % —" -f $s.OnTimeDelivery) -ForegroundColor $ontimeColor
    Write-Host " +--------------------------------------+" -ForegroundColor Cyan
    Write-Host ""

    return $s
}

# ============================================================
# INVOKE-VBAFTMSDAYREPLAY
# Full day compressed — 48 episodes at 30-min intervals
# ============================================================
function Invoke-VBAFTMSDayReplay {
    param(
        [string] $CustomerID = "NordLogistik",
        [switch] $FireEvents
    )

    Write-Host ""
    Write-Host " [TMS] Starting Day Replay � 48 episodes" -ForegroundColor Cyan
    Write-Host " [TMS] CustomerID: $CustomerID"           -ForegroundColor White
    Write-Host ""

    $results = @()

    for ($episode = 1; $episode -le 48; $episode++) {

        # Simulate time of day (30 min intervals from 00:00)
        $simulatedHour   = [Math]::Floor(($episode - 1) / 2)
        $simulatedMinute = if (($episode % 2) -eq 0) { 30 } else { 0 }
        $timeLabel       = "{0:00}:{1:00}" -f $simulatedHour, $simulatedMinute

        # Fire a random event occasionally
        if ($FireEvents -and ($episode -in @(10, 24, 38))) {
            Invoke-VBAFTMSEvent -Event "Random" -Rounds 4
        }

        $snapshot = Get-VBAFTMSAllSignals

        $result = [PSCustomObject]@{
            Episode        = $episode
            Time           = $timeLabel
            EmptyDriving   = $snapshot.EmptyDriving
            OnTimeDelivery = $snapshot.OnTimeDelivery
            Event          = $snapshot.ActiveEvent
        }

        $results += $result

        # Color coding
        $emptyColor  = if ($snapshot.EmptyDriving -gt 40)  { "Red"   } elseif ($snapshot.EmptyDriving -gt 25)  { "Yellow" } else { "Green" }
        $ontimeColor = if ($snapshot.OnTimeDelivery -lt 70) { "Red"   } elseif ($snapshot.OnTimeDelivery -lt 85) { "Yellow" } else { "Green" }

        Write-Host (" Ep {0,2} {1} Empty: " -f $episode, $timeLabel) -NoNewline -ForegroundColor White
        Write-Host ("{0,5} %" -f $snapshot.EmptyDriving) -NoNewline -ForegroundColor $emptyColor
        Write-Host (" OnTime: ") -NoNewline -ForegroundColor White
        Write-Host ("{0,5} %" -f $snapshot.OnTimeDelivery) -NoNewline -ForegroundColor $ontimeColor
        if ($snapshot.ActiveEvent -ne "None") {
            Write-Host (" [{0}]" -f $snapshot.ActiveEvent) -ForegroundColor Red
        } else {
            Write-Host ""
        }

        Start-Sleep -Milliseconds 200
    }

    Write-Host ""
    Write-Host " [TMS] Day Replay complete — 48 episodes done." -ForegroundColor Cyan

    # Summary
    $avgEmpty  = [Math]::Round(($results | Measure-Object -Property EmptyDriving  -Average).Average, 1)
    $avgOnTime = [Math]::Round(($results | Measure-Object -Property OnTimeDelivery -Average).Average, 1)
    $redEpisodes = ($results | Where-Object { $_.EmptyDriving -gt 40 -or $_.OnTimeDelivery -lt 70 }).Count

    Write-Host ""
    Write-Host " +--------------------------------------+" -ForegroundColor Cyan
    Write-Host " — Day Replay Summary —" -ForegroundColor Cyan
    Write-Host " —--------------------------------------—" -ForegroundColor Cyan
    Write-Host (" — Avg Empty Driving : {0,5} % —" -f $avgEmpty)   -ForegroundColor White
    Write-Host (" — Avg On-Time Delivery : {0,5} % —" -f $avgOnTime)  -ForegroundColor White
    Write-Host (" — Alert Episodes : {0,5} —" -f $redEpisodes) -ForegroundColor Yellow
    Write-Host " +--------------------------------------+" -ForegroundColor Cyan
    Write-Host ""

    return $results
}

# ============================================================
# START-VBAFTMSSCHEDULE
# Run in chosen mode continuously
# ============================================================
function Start-VBAFTMSSchedule {
    param(
        [Parameter(Mandatory)] [string] $CustomerID,
        [ValidateSet("Shadow","GoLive","Autonomy","RealTime")]
        [string] $Mode = "Shadow",
        [int]    $MaxRuns = 10
    )

    $intervalSeconds = switch ($Mode) {
        "Shadow"   { 1800 }   # 30 minutes
        "GoLive"   { 600  }   # 10 minutes
        "Autonomy" { 300  }   # 5 minutes
        "RealTime" { 5    }   # 5 seconds — demo mode
    }

    Write-Host ""
    Write-Host " [TMS] Starting Schedule" -ForegroundColor Cyan
    Write-Host (" Mode : {0}"   -f $Mode)                                          -ForegroundColor White
    Write-Host (" Interval : {0} seconds" -f $intervalSeconds)                         -ForegroundColor White
    Write-Host (" MaxRuns : {0}"   -f $MaxRuns)                                       -ForegroundColor White
    Write-Host " Press Ctrl+C to stop."                                                 -ForegroundColor Yellow
    Write-Host ""

    for ($run = 1; $run -le $MaxRuns; $run++) {

        Write-Host (" [Run {0}/{1}]" -f $run, $MaxRuns) -ForegroundColor DarkCyan

        $snapshot = Show-VBAFTMSStatus

        # Fire random event every ~8 runs
        if (($run % 8) -eq 0) {
            Invoke-VBAFTMSEvent -Event "Random" -Rounds 3
        }

        if ($run -lt $MaxRuns) {
            Write-Host (" Next run in {0} seconds..." -f $intervalSeconds) -ForegroundColor DarkGray
            Start-Sleep -Seconds $intervalSeconds
        }
    }

    Write-Host ""
    Write-Host " [TMS] Schedule complete." -ForegroundColor Cyan
    Write-Host ""
}

# ============================================================
# LOAD MESSAGE
# ============================================================
Write-Host ""
Write-Host " +------------------------------------------+" -ForegroundColor Cyan
Write-Host " — VBAF-Center TMS Simulator v1.0.0 —" -ForegroundColor Cyan
Write-Host " — 2 Signals — 3 Events — 4 Modes —" -ForegroundColor Cyan
Write-Host " +------------------------------------------+" -ForegroundColor Cyan
Write-Host ""
Write-Host " Signals : EmptyDriving % — OnTimeDelivery %"        -ForegroundColor White
Write-Host " Events : WeatherEvent — TrafficJam — VehicleBreakdown" -ForegroundColor White
Write-Host " Modes : Shadow(30m) — GoLive(10m) — Autonomy(5m) — RealTime" -ForegroundColor White
Write-Host ""
Write-Host " Quick start:"                                                    -ForegroundColor Yellow
Write-Host " Show-VBAFTMSStatus"                                              -ForegroundColor Green
Write-Host " Invoke-VBAFTMSDayReplay -CustomerID 'NordLogistik' -FireEvents"  -ForegroundColor Green
Write-Host " Start-VBAFTMSSchedule -CustomerID 'NordLogistik' -Mode Shadow -MaxRuns 10" -ForegroundColor Green
Write-Host " Start-VBAFTMSSchedule -CustomerID 'NordLogistik' -Mode RealTime -MaxRuns 2" -ForegroundColor Green
Write-Host ""