param([string]$Pattern = 'ALL')
$ErrorActionPreference = 'Stop'
$Workspace = 'C:\Users\user\Documents\New project'
$OutRoot = Join-Path $Workspace 'KOUCHA_GOLD_TA9_SHADOW_RUNTIME_REGRESSION_AUDIT'
$SourceManifest = Join-Path $Workspace 'KOUCHA_GOLD_S2_PRE_HARDSTOP_P1_COMPARE\test_manifest.csv'
$TerminalExe = 'C:\Program Files\XMTrading MT5\terminal64.exe'
$TesterRoot = 'C:\Users\user\AppData\Roaming\MetaQuotes\Tester\2FA8A7E69CED7DC259B1AD86A247F675'
$AgentRoot = Join-Path $TesterRoot 'Agent-127.0.0.1-3000'
$AgentFiles = Join-Path $AgentRoot 'MQL5\Files'
$TerminalExperts = 'C:\Users\user\AppData\Roaming\MetaQuotes\Terminal\2FA8A7E69CED7DC259B1AD86A247F675\MQL5\Experts'
$TerminalEx5 = Join-Path $TerminalExperts 'KOUCHA_GOLD_KIWAMI_SURVIVAL_TICK.ex5'
$BeforeEx5 = Join-Path $OutRoot 'compile_baseline_workspace\KOUCHA_GOLD_KIWAMI_SURVIVAL_TICK.ex5'
$AfterEx5 = Join-Path $OutRoot 'compile_shadow_workspace\KOUCHA_GOLD_KIWAMI_SURVIVAL_TICK.ex5'
$StatusPath = Join-Path $OutRoot 'regression_run_status.csv'
$ExecutionManifestPath = Join-Path $OutRoot 'regression_execution_manifest.csv'
$AuthoritativeManifestPath = Join-Path $OutRoot 'authoritative_six_run_manifest.csv'
$InputComparePath = Join-Path $OutRoot 'input_effective_compare.csv'
$EnvManifestCsv = Join-Path $OutRoot 'tester_environment_manifest.csv'
$EnvManifestTxt = Join-Path $OutRoot 'tester_environment_manifest.txt'

foreach($d in @('configs','sets','reports','journals','agent_logs','expert_logs','shadow_logs','canonical','original_inputs')){
  New-Item -ItemType Directory -Path (Join-Path $OutRoot $d) -Force | Out-Null
}

function CsvLine($values) { return (($values | ForEach-Object { '"' + ([string]$_ -replace '"','""') + '"' }) -join ',') }
function Add-Status($RunName,$Phase,$StartTime,$EndTime,$ExitCode,$IniPath,$Note) {
  if(!(Test-Path $StatusPath)) { 'run_name,phase,start_time,end_time,elapsed_seconds,exit_code,ini_path,note' | Set-Content -LiteralPath $StatusPath -Encoding UTF8 }
  $elapsed = if($StartTime -and $EndTime){ [int]($EndTime-$StartTime).TotalSeconds } else { '' }
  Add-Content -LiteralPath $StatusPath -Encoding UTF8 -Value (CsvLine @($RunName,$Phase,$StartTime.ToString('s'),$EndTime.ToString('s'),$elapsed,$ExitCode,$IniPath,$Note))
}
function Stop-TestProcesses {
  Get-CimInstance Win32_Process | Where-Object { $_.Name -match 'terminal64|metatester64' } | ForEach-Object { Stop-Process -Id $_.ProcessId -Force -ErrorAction SilentlyContinue }
}
function Get-AgentLogPath { return (Join-Path $AgentRoot ('logs\' + (Get-Date -Format 'yyyyMMdd') + '.log')) }
function Get-FileSha($p) { if(Test-Path -LiteralPath $p){ return (Get-FileHash -LiteralPath $p -Algorithm SHA256).Hash } return '' }
function Read-ConfigValue($Path,$Key) {
  $prefix = "$Key="
  foreach($line in Get-Content -LiteralPath $Path -Encoding Unicode) { if($line.StartsWith($prefix)) { return $line } }
  return ''
}
function Value-Only($Line) {
  if(!$Line -or $Line.IndexOf('=') -lt 0) { return '' }
  $v = $Line.Split('=',2)[1]
  if($v.Contains('||')) { return $v.Split('||',2)[0] }
  return $v
}
function Set-KeyLine($lines, $key, $lineValue) {
  $found = $false
  $out = New-Object System.Collections.Generic.List[string]
  foreach($line in $lines){
    if($line.StartsWith($key + '=')) { $out.Add($lineValue); $found = $true } else { $out.Add($line) }
  }
  if(!$found) { $out.Add($lineValue) }
  return $out.ToArray()
}
function Remove-KeyLine($lines, $key) { return @($lines | Where-Object { -not $_.StartsWith($key + '=') }) }
function Copy-IfExists($Source,$Destination) { if(Test-Path -LiteralPath $Source){ Copy-Item -LiteralPath $Source -Destination $Destination -Force; return $Source } return '' }
function Read-NewLogLines($AgentLog,$FromLine) {
  if(!(Test-Path -LiteralPath $AgentLog)) { return @() }
  $lines = @(Get-Content -LiteralPath $AgentLog)
  if($lines.Count -le $FromLine) { return @() }
  return @($lines[$FromLine..($lines.Count - 1)])
}
function Clear-AgentFiles($InventoryPath) {
  $patterns = @('KOUCHA_GOLD_*.csv','TA9SHADOW_*.csv')
  $items = @()
  foreach($pat in $patterns){ $items += @(Get-ChildItem -Path $AgentFiles -Filter $pat -File -ErrorAction SilentlyContinue) }
  $items | Sort-Object FullName -Unique | Select-Object FullName,Length,LastWriteTime | Export-Csv -LiteralPath $InventoryPath -NoTypeInformation -Encoding UTF8
  foreach($item in ($items | Sort-Object FullName -Unique)){ Remove-Item -LiteralPath $item.FullName -Force -ErrorAction SilentlyContinue }
}
function Copy-AgentOutputs($RunDir,$RunName,$AgentLog,$LogStartLine) {
  Get-ChildItem -Path $AgentFiles -File -Filter 'KOUCHA_GOLD_*.csv' -ErrorAction SilentlyContinue | ForEach-Object {
    Copy-Item -LiteralPath $_.FullName -Destination (Join-Path $RunDir ($RunName + '_' + $_.Name)) -Force
  }
  Get-ChildItem -Path $AgentFiles -File -Filter 'TA9SHADOW_*.csv' -ErrorAction SilentlyContinue | ForEach-Object {
    $dest = Join-Path $RunDir ($RunName + '_' + $_.Name)
    Copy-Item -LiteralPath $_.FullName -Destination $dest -Force
    Copy-Item -LiteralPath $_.FullName -Destination (Join-Path (Join-Path $OutRoot 'shadow_logs') ($RunName + '_' + $_.Name)) -Force
  }
  Copy-IfExists -Source $AgentLog -Destination (Join-Path $RunDir ($RunName + '_tester.log')) | Out-Null
  $newLines = Read-NewLogLines $AgentLog $LogStartLine
  $newLines | Set-Content -LiteralPath (Join-Path $RunDir ($RunName + '_tester_window.log')) -Encoding UTF8
  Get-ChildItem -Path $AgentFiles -File | Select-Object Name,Length,LastWriteTime | Export-Csv -LiteralPath (Join-Path $RunDir ($RunName + '_agent_files_after.csv')) -NoTypeInformation -Encoding UTF8
}

if(Test-Path $StatusPath){ Remove-Item $StatusPath -Force }
'run_group_id,series,run_name,original_log_id,period_start,period_end,deposit,deposit_currency,leverage,symbol,timeframe,tester_model,execution_mode,spread_mode,forward_mode,optimization_mode,visual_mode,ea_input_set,set_sha256,ini_path,source_sha,ex5_sha,shadow_flag' | Set-Content -LiteralPath $ExecutionManifestPath -Encoding UTF8
'run_group_id,original_log_id,period_start,period_end,deposit,deposit_currency,leverage,symbol,symbol_specification_source,timeframe,tester_model,execution_mode,spread_mode,forward_mode,optimization_mode,visual_mode,ea_input_set,set_file_sha256,news_input_external_files,external_file_sha256,original_result_source,original_basket_count,original_trade_deal_count,original_final_balance,original_maxdd,original_hardstop_count,original_hte_count,original_recoveryclose_count,original_basketclose_count,original_unresolved_count' | Set-Content -LiteralPath $AuthoritativeManifestPath -Encoding UTF8
'run_group_id,setting_key,input_name,A_value,B_value,C_value,status' | Set-Content -LiteralPath $InputComparePath -Encoding UTF8

$terminalVersion = (Get-Item $TerminalExe).VersionInfo.FileVersion
$agentPath = Join-Path $AgentRoot 'metatester64.exe'
$agentVersion = if(Test-Path $agentPath){(Get-Item $agentPath).VersionInfo.FileVersion}else{''}
$envRows = @([pscustomobject]@{key='terminal_exe';value=$TerminalExe},[pscustomobject]@{key='terminal_version';value=$terminalVersion},[pscustomobject]@{key='agent_root';value=$AgentRoot},[pscustomobject]@{key='agent_version';value=$agentVersion},[pscustomobject]@{key='tester_root';value=$TesterRoot})
$envRows | Export-Csv -LiteralPath $EnvManifestCsv -NoTypeInformation -Encoding UTF8
$envRows | Format-List | Out-String | Set-Content -LiteralPath $EnvManifestTxt -Encoding UTF8

$baseRows = Import-Csv -LiteralPath $SourceManifest | Where-Object { $_.Variant -eq 'P0_BASELINE' }
if($baseRows.Count -ne 6){ throw "Expected 6 P0 baseline rows, found $($baseRows.Count)" }
if($Pattern -ne 'ALL'){ $baseRows = $baseRows | Where-Object { $_.TestName -like "*$Pattern*" -or $_.Pattern -like "*$Pattern*" } }

foreach($base in $baseRows){
  $group = "$($base.InitialDeposit)_$($base.PeriodLabel)_$($base.PeriodStart)_$($base.PeriodEnd)"
  $origTrade = Join-Path (Split-Path -Parent $base.Ini) ($base.TestName + '_trade_events.csv')
  $origPerf = Join-Path (Split-Path -Parent $base.Ini) ($base.TestName + '_performance_stats.csv')
  $tradeCount = if(Test-Path $origTrade){ [Math]::Max(0, (@(Get-Content -LiteralPath $origTrade).Count - 1)) } else { '' }
  $finalBalance = ''
  if(Test-Path $origTrade){
    $last = Import-Csv -LiteralPath $origTrade | Select-Object -Last 1
    if($last){ $finalBalance = $last.Balance }
  }
  Add-Content -LiteralPath $AuthoritativeManifestPath -Encoding UTF8 -Value (CsvLine @($group,$base.TestName,$base.PeriodStart,$base.PeriodEnd,$base.InitialDeposit,'JPY','1:888','GOLD','P0 S2 manifest ini preflight','M5','0','0','tester fixed from ini','0','0','0',$base.Set,(Get-FileSha $base.Set),'news_blackout.csv','NOT_REHASHED',$origTrade,'UNKNOWN',$tradeCount,$finalBalance,'UNKNOWN','UNKNOWN','UNKNOWN','UNKNOWN','UNKNOWN','UNKNOWN'))
  $seriesDefs = @(
    [pscustomobject]@{Series='A'; Label='FRESH_BASELINE'; ShadowFlag='ABSENT'; Ex5=$BeforeEx5; SourceSha='30490B2D7AAC6C0197CC65B326A7728E82A8E62759E7E9202741EF851430CA9B'},
    [pscustomobject]@{Series='B'; Label='SHADOW_OFF'; ShadowFlag='false'; Ex5=$AfterEx5; SourceSha='1353718F46D727DB775827AAF30F86EC790056CB59CE46EB00D5BAD563EF1DE3'},
    [pscustomobject]@{Series='C'; Label='SHADOW_ON'; ShadowFlag='true'; Ex5=$AfterEx5; SourceSha='1353718F46D727DB775827AAF30F86EC790056CB59CE46EB00D5BAD563EF1DE3'}
  )
  foreach($sd in $seriesDefs){
    $runName = "TA9_$($sd.Series)_$($sd.Label)_$($base.InitialDeposit)_$($base.PeriodLabel)_M5_$($base.PeriodStart.Replace('.',''))_$($base.PeriodEnd.Replace('.',''))"
    $runDir = Join-Path $OutRoot $runName
    New-Item -ItemType Directory -Path $runDir -Force | Out-Null
    $ini = Join-Path $runDir ($runName + '.ini')
    $set = Join-Path $runDir ($runName + '.set')
    $iniLines = @(Get-Content -LiteralPath $base.Ini -Encoding Unicode)
    $setLines = @(Get-Content -LiteralPath $base.Set -Encoding Unicode)
    if($sd.Series -eq 'A'){
      $iniLines = Remove-KeyLine $iniLines 'EnableTA9ShadowLogging'
      $setLines = Remove-KeyLine $setLines 'EnableTA9ShadowLogging'
    } else {
      $line = "EnableTA9ShadowLogging=$($sd.ShadowFlag)||false||0||true||N"
      $iniLines = Set-KeyLine $iniLines 'EnableTA9ShadowLogging' $line
      $setLines = Set-KeyLine $setLines 'EnableTA9ShadowLogging' $line
    }
    $iniLines | Set-Content -LiteralPath $ini -Encoding Unicode
    $setLines | Set-Content -LiteralPath $set -Encoding Unicode
    Copy-Item -LiteralPath $ini -Destination (Join-Path (Join-Path $OutRoot 'configs') ($runName + '.ini')) -Force
    Copy-Item -LiteralPath $set -Destination (Join-Path (Join-Path $OutRoot 'sets') ($runName + '.set')) -Force
    Add-Content -LiteralPath $ExecutionManifestPath -Encoding UTF8 -Value (CsvLine @($group,$sd.Series,$runName,$base.TestName,$base.PeriodStart,$base.PeriodEnd,$base.InitialDeposit,'JPY','1:888','GOLD','M5','0','0','tester fixed from ini','0','0','0',$set,(Get-FileSha $set),$ini,$sd.SourceSha,(Get-FileSha $sd.Ex5),$sd.ShadowFlag))
  }
  Add-Content -LiteralPath $InputComparePath -Encoding UTF8 -Value (CsvLine @($group,"$($base.InitialDeposit)_$($base.PeriodLabel)",'EnableTA9ShadowLogging','ABSENT','false','true','OK'))
}

$execRows = Import-Csv -LiteralPath $ExecutionManifestPath
foreach($run in $execRows){
  if(!$run.run_name){ continue }
  Stop-TestProcesses
  Start-Sleep -Seconds 2
  $runDir = Join-Path $OutRoot $run.run_name
  $selectedEx5 = if($run.series -eq 'A'){ $BeforeEx5 } else { $AfterEx5 }
  Copy-Item -LiteralPath $selectedEx5 -Destination $TerminalEx5 -Force
  $beforeInventory = Join-Path $runDir ($run.run_name + '_agent_files_before_delete.csv')
  Clear-AgentFiles -InventoryPath $beforeInventory
  $AgentLog = Get-AgentLogPath
  $logStartLine = 0
  if(Test-Path -LiteralPath $AgentLog){ $logStartLine = @(Get-Content -LiteralPath $AgentLog).Count }
  $start = Get-Date
  Add-Status $run.run_name 'START' $start $start '' $run.ini_path 'starting terminal backtest'
  $proc = Start-Process -FilePath $TerminalExe -ArgumentList "/config:`"$($run.ini_path)`"" -WindowStyle Hidden -PassThru
  $expectedInitial = "initial deposit $($run.deposit) JPY, leverage 1:888"
  $initialLine = ''
  $preflightOk = $false
  for($j=0; $j -lt 90; $j++){
    Start-Sleep -Seconds 2
    $newLines = Read-NewLogLines $AgentLog $logStartLine
    $initialLine = ($newLines | Select-String -Pattern 'initial deposit' | Select-Object -First 1).Line
    if($initialLine){ if($initialLine -match [regex]::Escape($expectedInitial)){ $preflightOk = $true }; break }
    if($proc.HasExited){ break }
  }
  if(!$preflightOk){
    Add-Status $run.run_name 'PREFLIGHT_FAIL' $start (Get-Date) '' $run.ini_path $initialLine
    if(-not $proc.HasExited){ Stop-Process -Id $proc.Id -Force -ErrorAction SilentlyContinue }
    throw "Runtime preflight failed for $($run.run_name): $initialLine"
  }
  Add-Status $run.run_name 'PREFLIGHT_OK' $start (Get-Date) '' $run.ini_path $initialLine
  $finishedDetected = $false
  while(-not $proc.HasExited){
    Start-Sleep -Seconds 10
    $newLines = Read-NewLogLines $AgentLog $logStartLine
    if($newLines -match 'thread finished|shutdown finished|MetaTester 5 stopped'){
      $finishedDetected = $true
      try{ [void]$proc.CloseMainWindow(); Start-Sleep -Seconds 5 } catch {}
      if(-not $proc.HasExited){ Stop-Process -Id $proc.Id -Force -ErrorAction SilentlyContinue }
      break
    }
  }
  $end = Get-Date
  $exitCode = ''
  try{ $exitCode = $proc.ExitCode } catch {}
  Add-Status $run.run_name 'END' $start $end $exitCode $run.ini_path ($(if($finishedDetected){'tester thread finished'}else{'terminal process ended'}))
  Copy-AgentOutputs $runDir $run.run_name $AgentLog $logStartLine
  $shadowCount = @(Get-ChildItem -Path $runDir -File -Filter ($run.run_name + '_TA9SHADOW_*.csv') -ErrorAction SilentlyContinue).Count
  if($run.series -eq 'B' -and $shadowCount -ne 0){ Add-Status $run.run_name 'SHADOW_FILE_UNEXPECTED' $start (Get-Date) $exitCode $run.ini_path "shadow_files=$shadowCount"; throw "Shadow OFF generated shadow files for $($run.run_name)" }
  if($run.series -eq 'C' -and $shadowCount -eq 0){ Add-Status $run.run_name 'SHADOW_FILE_MISSING' $start (Get-Date) $exitCode $run.ini_path 'shadow_files=0'; throw "Shadow ON generated no shadow files for $($run.run_name)" }
  Add-Status $run.run_name 'COPY' $start (Get-Date) $exitCode $run.ini_path "copied outputs shadow_files=$shadowCount"
}
Stop-TestProcesses
Copy-Item -LiteralPath $AfterEx5 -Destination $TerminalEx5 -Force
Write-Host "Finished TA9 shadow runtime regression in $OutRoot"
