$ErrorActionPreference = 'Stop'

function Assert-Equal($expected, $actual, [string]$message) {
    if ($expected -ne $actual) {
        throw "$message Expected: '$expected'. Actual: '$actual'."
    }
}

function Assert-True([bool]$condition, [string]$message) {
    if (-not $condition) {
        throw $message
    }
}

$repositoryRoot = Split-Path -Parent $PSScriptRoot
$assemblyPath = Join-Path $repositoryRoot 'bin\Debug\netstandard2.0\ClumsyPilot.dll'
$fixturePath = Join-Path $repositoryRoot 'ParkrobTrajplanner\PathSmoothing\Test\Fixtures\local-g2-diagnostic-single-turn.json'

if (-not (Test-Path -LiteralPath $assemblyPath)) {
    throw "ClumsyPilot assembly was not found: $assemblyPath"
}

$assembly = [System.Reflection.Assembly]::LoadFrom($assemblyPath)
$loaderType = $assembly.GetType('MultiWheelC.TrajectoryPlanning.PathSmoothing.Test.LocalG2DiagnosticEvidenceLoader', $true)
$loader = [System.Activator]::CreateInstance($loaderType)
$loadAndVerify = $loaderType.GetMethod('LoadAndVerify')
$evidence = $loadAndVerify.Invoke($loader, @($fixturePath))

Assert-Equal 'single-turn' $evidence.ScenarioId 'Diagnostic evidence scenario must be stable.'
Assert-Equal 'single-turn/s0/r0/w5/seed2' $evidence.CandidateStableKey 'Diagnostic evidence key must be stable.'
Assert-Equal 5 $evidence.CandidateIndex 'Diagnostic evidence candidate index must be stable.'
Assert-Equal 10 $evidence.CandidatePoints.Count 'Diagnostic evidence must retain all ten recorded samples.'
Assert-Equal 'InsufficientClearance' $evidence.EvaluatorResult 'Diagnostic evidence must retain the observed evaluator result.'
Assert-Equal 'Clearance' $evidence.StopGate 'Diagnostic evidence must retain the observed stop gate.'
Assert-Equal 'Unchanged' $evidence.PublishedStatus 'Diagnostic evidence must retain the strict final status.'

function Assert-Rejected([string]$tamperedContent, [string]$message) {
    $temporaryEvidencePath = Join-Path ([System.IO.Path]::GetTempPath()) ("local-g2-diagnostic-evidence-{0}.json" -f [System.Guid]::NewGuid())
    try {
        [System.IO.File]::WriteAllText($temporaryEvidencePath, $tamperedContent, [System.Text.Encoding]::UTF8)

        $rejected = $false
        try {
            $null = $loadAndVerify.Invoke($loader, @($temporaryEvidencePath))
        }
        catch {
            $rejected = $true
        }

        Assert-True $rejected $message
    }
    finally {
        if (Test-Path -LiteralPath $temporaryEvidencePath) {
            Remove-Item -LiteralPath $temporaryEvidencePath -Force
        }
    }
}

$fixtureContent = Get-Content -LiteralPath $fixturePath -Raw
Assert-Rejected ($fixtureContent.Replace('"StopGate": "Clearance"', '"StopGate": "Collision"')) 'Tampered stop gate must be rejected.'
Assert-Rejected ($fixtureContent.Replace('"HeadingRadians": 0.835253334801853', '"HeadingRadians": 0.935253334801853')) 'Tampered middle candidate heading must be rejected.'
Assert-Rejected ($fixtureContent.Replace('"WindowStartArcLengthMeters": 1.9199999999999982', '"WindowStartArcLengthMeters": 1.8199999999999982')) 'Tampered window must be rejected even when candidate endpoints are unchanged.'
Assert-Rejected ([regex]::Replace($fixtureContent, '(?m)^\s*"SegmentIndex": 0,\r?\n', '')) 'Evidence missing SegmentIndex must be rejected.'
