param(
  [string]$OutRoot = 'C:\Users\user\Documents\New project\KOUCHA_GOLD_BASKET_CLOSE_PROFIT_COMPARE',
  [string]$TerminalExe = 'C:\Program Files\XMTrading MT5\terminal64.exe',
  [string]$AgentRoot = 'C:\Users\user\AppData\Roaming\MetaQuotes\Tester\2FA8A7E69CED7DC259B1AD86A247F675\Agent-127.0.0.1-3000',
  [string]$Pattern = 'ALL',
  [int]$PollSeconds = 5
)
$ErrorActionPreference = 'Stop'
function CsvEscape([object]$value) { $text=[string]$value; '"' + ($text -replace '"','""') + '"' }
function Add-StatusRow([string]$TestName,[string]$PatternName,[string]$Segment,[string]$Phase,[datetime]$StartTime,[datetime]$EndTime,[int]$ElapsedSeconds,[object]$ExitCode,[string]$IniPath,[string]$Note) {
  $line=@((CsvEscape $TestName),(CsvEscape $PatternName),(CsvEscape $Segment),(CsvEscape $Phase),(CsvEscape $StartTime.ToString('s')),(CsvEscape $EndTime.ToString('s')),(CsvEscape $ElapsedSeconds),(CsvEscape $ExitCode),(CsvEscape $IniPath),(CsvEscape $Note)) -join ','
  Add-Content -LiteralPath $script:StatusPath -Value $line -Encoding UTF8
}
function Add-PreflightRow([object]$test,[string]$check,[string]$expected,[string]$actual,[string]$status,[string]$evidence) {
  if (!(Test-Path -LiteralPath $script:PreflightPath)) { 'TestName,Pattern,Segment,CheckName,Expected,Actual,Status,Evidence,Note' | Set-Content -LiteralPath $script:PreflightPath -Encoding UTF8 }
  $line=@((CsvEscape $test.TestName),(CsvEscape $test.Pattern),(CsvEscape $test.Segment),(CsvEscape $check),(CsvEscape $expected),(CsvEscape $actual),(CsvEscape $status),(CsvEscape $evidence),(CsvEscape 'preflight')) -join ','
  Add-Content -LiteralPath $script:PreflightPath -Value $line -Encoding UTF8
}
function Stop-AllMt5 { Get-CimInstance Win32_Process -ErrorAction SilentlyContinue | Where-Object { $_.Name -in @('terminal64.exe','metatester64.exe') } | ForEach-Object { Stop-Process -Id $_.ProcessId -Force -ErrorAction SilentlyContinue } }
function Get-ActiveThisRun { @(Get-CimInstance Win32_Process -ErrorAction SilentlyContinue | Where-Object { $_.Name -in @('terminal64.exe','metatester64.exe') -and $_.CommandLine -like "*$OutRoot*" }) }
function Wait-ForExternalToFinish { while (@(Get-ActiveThisRun).Count -gt 0) { Start-Sleep -Seconds $PollSeconds }; Start-Sleep -Seconds 2 }
function Get-CompletedNames { if (!(Test-Path -LiteralPath $script:StatusPath)) { return @() }; try { @(Import-Csv -LiteralPath $script:StatusPath | Where-Object { $_.Phase -eq 'END' } | Select-Object -ExpandProperty TestName -Unique) } catch { @() } }
function Get-SetValue([string]$SetPath,[string]$Name) { $line=(Get-Content -LiteralPath $SetPath | Where-Object { $_ -like "$Name=*" } | Select-Object -First 1); if(!$line){return ''}; (($line -split '=',2)[1] -split '\|\|')[0] }
function Validate-StaticInputs([object]$test) {
  $ini=Get-Content -LiteralPath $test.Ini
  $checks=@(
    @{Name='Deposit';Expected='50000';Actual=(($ini|Where-Object{$_ -eq 'Deposit=50000'}|Select-Object -First 1) -replace 'Deposit=','')},
    @{Name='Leverage';Expected='1:888';Actual=(($ini|Where-Object{$_ -eq 'Leverage=1:888'}|Select-Object -First 1) -replace 'Leverage=','')},
    @{Name='Symbol';Expected='GOLD';Actual=(($ini|Where-Object{$_ -eq 'Symbol=GOLD'}|Select-Object -First 1) -replace 'Symbol=','')},
    @{Name='Period';Expected='M5';Actual=(($ini|Where-Object{$_ -eq 'Period=M5'}|Select-Object -First 1) -replace 'Period=','')},
    @{Name='Model';Expected='0';Actual=(($ini|Where-Object{$_ -eq 'Model=0'}|Select-Object -First 1) -replace 'Model=','')},
    @{Name='UseBacktestFastCompareMode';Expected='true';Actual=(Get-SetValue $test.Set 'UseBacktestFastCompareMode')},
    @{Name='UseBacktestDiagnosticMode';Expected='false';Actual=(Get-SetValue $test.Set 'UseBacktestDiagnosticMode')},
    @{Name='UseDxyVixOnlyCache';Expected='true';Actual=(Get-SetValue $test.Set 'UseDxyVixOnlyCache')},
    @{Name='DxyVixOnlyCacheSeconds';Expected='5';Actual=(Get-SetValue $test.Set 'DxyVixOnlyCacheSeconds')},
    @{Name='UsePerformanceCache';Expected='false';Actual=(Get-SetValue $test.Set 'UsePerformanceCache')},
    @{Name='DisableMaGoldTechnicalCacheForSafety';Expected='true';Actual=(Get-SetValue $test.Set 'DisableMaGoldTechnicalCacheForSafety')},
    @{Name='KeepEntryCriticalFiltersTickExact';Expected='true';Actual=(Get-SetValue $test.Set 'KeepEntryCriticalFiltersTickExact')},
    @{Name='BacktestPatternName';Expected=$test.Pattern;Actual=(Get-SetValue $test.Set 'BacktestPatternName')}
  )
  $ok=$true
  foreach($c in $checks){ $status= if([string]$c.Actual -eq [string]$c.Expected){'OK'}else{'NG'}; if($status -eq 'NG'){$ok=$false}; Add-PreflightRow $test $c.Name $c.Expected $c.Actual $status $test.Set }
  return $ok
}
function Run-OneTest([object]$test) {
  if(!(Validate-StaticInputs $test)){ throw "Static preflight failed for $($test.TestName)" }
  $agentFiles=Join-Path $AgentRoot 'MQL5\Files'
  $agentLog=Join-Path $AgentRoot ('logs\' + (Get-Date -Format 'yyyyMMdd') + '.log')
  $names=@('KOUCHA_GOLD_KIWAMI_TRADE_EVENTS.csv','KOUCHA_GOLD_ENTRY_OPPORTUNITY_AUDIT.csv','KOUCHA_GOLD_KIWAMI_SURVIVAL_TICK_LOG.csv','KOUCHA_GOLD_ENTRY_DECISION_TRACE.csv','KOUCHA_GOLD_REACTIVE_HEDGE_ELIGIBILITY_TRACE.csv','KOUCHA_GOLD_PERFORMANCE_STATS.csv','KOUCHA_GOLD_COPYBUFFER_BREAKDOWN.csv')
  Stop-AllMt5; Start-Sleep -Seconds 2
  foreach($name in $names){ $p=Join-Path $agentFiles $name; if(Test-Path -LiteralPath $p){ Remove-Item -LiteralPath $p -Force -ErrorAction SilentlyContinue } }
  $logStart=0; if(Test-Path -LiteralPath $agentLog){ $logStart=@(Get-Content -LiteralPath $agentLog).Count }
  $start=Get-Date; Add-StatusRow $test.TestName $test.Pattern $test.Segment 'START' $start $start 0 '' $test.Ini 'starting'
  $proc=Start-Process -FilePath $TerminalExe -ArgumentList "/config:`"$($test.Ini)`"" -WindowStyle Hidden -PassThru
  $initial=''; $preOk=$false
  for($i=0;$i -lt 90;$i++){ Start-Sleep -Seconds 2; if(Test-Path -LiteralPath $agentLog){ $lines=@(Get-Content -LiteralPath $agentLog); if($lines.Count -gt $logStart){ $new=$lines[$logStart..($lines.Count-1)]; $initial=($new|Select-String -Pattern 'initial deposit'|Select-Object -First 1).Line; if($initial){ if($initial -match 'initial deposit 50000 JPY, leverage 1:888'){$preOk=$true}; break } } }; if($proc.HasExited){break} }
  $now=Get-Date; Add-PreflightRow $test 'runtime initial deposit/leverage' 'initial deposit 50000 JPY, leverage 1:888' $initial $(if($preOk){'OK'}else{'NG'}) $agentLog
  Add-StatusRow $test.TestName $test.Pattern $test.Segment 'PREFLIGHT_OK' $start $now ([int]($now-$start).TotalSeconds) '' $test.Ini $initial
  if(!$preOk){ if(!$proc.HasExited){Stop-Process -Id $proc.Id -Force -ErrorAction SilentlyContinue}; throw "Runtime preflight failed for $($test.TestName): $initial" }
  $finished=$false
  while(!$proc.HasExited){ Start-Sleep -Seconds $PollSeconds; if(Test-Path -LiteralPath $agentLog){ $lines=@(Get-Content -LiteralPath $agentLog); if($lines.Count -gt $logStart){ $new=$lines[$logStart..($lines.Count-1)]; if($new -match 'thread finished|shutdown finished|MetaTester 5 stopped'){ $finished=$true; try{[void]$proc.CloseMainWindow(); Start-Sleep -Seconds 3}catch{}; if(!$proc.HasExited){Stop-Process -Id $proc.Id -Force -ErrorAction SilentlyContinue}; break } } } }
  $end=Get-Date; $elapsed=[int]($end-$start).TotalSeconds; Add-StatusRow $test.TestName $test.Pattern $test.Segment 'END' $start $end $elapsed $proc.ExitCode $test.Ini $(if($finished){'tester thread finished'}else{'terminal process ended'})
  $dir=Split-Path -Parent $test.Ini
  foreach($name in $names){ $src=Join-Path $agentFiles $name; if(Test-Path -LiteralPath $src){ Copy-Item -LiteralPath $src -Destination (Join-Path $dir ($test.TestName + '_' + $name)) -Force } }
  if(Test-Path -LiteralPath $agentLog){ $current=Join-Path $dir ($test.TestName + '_tester_current_run_only.log'); $lines=@(Get-Content -LiteralPath $agentLog); if($lines.Count -gt $logStart){ $lines[$logStart..($lines.Count-1)] | Set-Content -LiteralPath $current -Encoding UTF8 }; Copy-Item -LiteralPath $agentLog -Destination (Join-Path $dir ($test.TestName + '_tester.log')) -Force }
  Write-Host "$($test.TestName) done elapsed=$elapsed finished=$finished"
}
$manifestPath=Join-Path $OutRoot 'benchmark_manifest.csv'
$script:StatusPath=Join-Path $OutRoot 'run_status.csv'
$script:PreflightPath=Join-Path $OutRoot 'input_preflight_validation.csv'
if(!(Test-Path -LiteralPath $manifestPath)){throw "Manifest not found: $manifestPath"}
if(!(Test-Path -LiteralPath $script:StatusPath)){ 'TestName,Pattern,Segment,Phase,StartTime,EndTime,ElapsedSeconds,ExitCode,IniPath,Note' | Set-Content -LiteralPath $script:StatusPath -Encoding UTF8 }
if(!(Test-Path -LiteralPath $script:PreflightPath)){ 'TestName,Pattern,Segment,CheckName,Expected,Actual,Status,Evidence,Note' | Set-Content -LiteralPath $script:PreflightPath -Encoding UTF8 }
$tests=@(Import-Csv -LiteralPath $manifestPath)
if($Pattern -ne 'ALL'){ $tests=@($tests|Where-Object{$_.Pattern -eq $Pattern -or $_.TestName -like "$Pattern*" -or $_.Segment -eq $Pattern}) }
foreach($test in $tests){ Wait-ForExternalToFinish; $completed=@(Get-CompletedNames); if($completed -contains $test.TestName){Write-Host "skip completed $($test.TestName)"; continue}; Run-OneTest $test }
Write-Host 'basket close tests complete'
