#!/usr/bin/env pwsh
# test_control_mode.ps1
# Integration tests for tmux-compatible control mode (-C / -CC)
# Tests: basic connection, command dispatch, %begin/%end framing,
#        list-windows, list-panes, new-window, send-keys, capture-pane,
#        notification emission, echo mode vs no-echo mode

$ErrorActionPreference = "Continue"
$exe = "$PSScriptRoot\..\target\release\psmux.exe"
if (-not (Test-Path $exe)) { $exe = "$PSScriptRoot\..\target\debug\psmux.exe" }
if (-not (Test-Path $exe)) { $exe = (Get-Command psmux -ErrorAction SilentlyContinue).Source }
if (-not $exe -or -not (Test-Path $exe)) { Write-Error "psmux binary not found"; exit 1 }

$SESSION = "test-ctrl-mode"
$results = @()

function Add-Result($name, $pass, $detail="") {
    $script:results += [PSCustomObject]@{
        Test=$name
        Result=if($pass){"PASS"}else{"FAIL"}
        Detail=$detail
    }
    $mark = if($pass) { "[PASS]" } else { "[FAIL]" }
    $color = if($pass) { "Green" } else { "Red" }
    Write-Host "  $mark $name$(if($detail){' '+$detail}else{''})" -ForegroundColor $color
}

# Helper: run a control mode session, feed commands, return output lines
function Invoke-ControlMode {
    param(
        [string]$Mode = "-CC",  # -C or -CC
        [string[]]$Commands,
        [int]$TimeoutMs = 5000
    )
    # Build a script that pipes commands into control mode
    $cmdInput = ($Commands -join "`n") + "`n"
    $tempIn = [System.IO.Path]::GetTempFileName()
    [System.IO.File]::WriteAllText($tempIn, $cmdInput)

    $env:PSMUX_SESSION_NAME = $SESSION
    try {
        $proc = Start-Process -FilePath $exe -ArgumentList $Mode -RedirectStandardInput $tempIn `
            -RedirectStandardOutput "$env:TEMP\psmux_ctrl_out.txt" `
            -RedirectStandardError "$env:TEMP\psmux_ctrl_err.txt" `
            -PassThru -NoNewWindow

        # Wait for commands to be processed
        $finished = $proc.WaitForExit($TimeoutMs)
        if (-not $finished) {
            $proc.Kill()
            Start-Sleep -Milliseconds 500
        }

        $output = Get-Content "$env:TEMP\psmux_ctrl_out.txt" -ErrorAction SilentlyContinue
        return $output
    } finally {
        Remove-Item $tempIn -Force -ErrorAction SilentlyContinue
        Remove-Item "$env:TEMP\psmux_ctrl_out.txt" -Force -ErrorAction SilentlyContinue
        Remove-Item "$env:TEMP\psmux_ctrl_err.txt" -Force -ErrorAction SilentlyContinue
        Remove-Item env:\PSMUX_SESSION_NAME -ErrorAction SilentlyContinue
    }
}

Write-Host "`n================================================" -ForegroundColor Cyan
Write-Host "Control Mode (-C / -CC) Integration Test Suite" -ForegroundColor Cyan
Write-Host "================================================`n" -ForegroundColor Cyan

# ---- Cleanup ----
& $exe kill-session -t $SESSION 2>$null
& $exe kill-server 2>$null
Start-Sleep -Seconds 1

# ---- Setup: create a detached session ----
Write-Host "Setting up test session..." -ForegroundColor Yellow
& $exe new-session -d -s $SESSION -x 120 -y 30 2>$null
Start-Sleep -Seconds 3

# ============================================================
# TEST 1: Basic -CC connection and list-windows
# ============================================================
Write-Host "`n--- Test 1: Basic -CC connection and list-windows ---" -ForegroundColor Cyan

$output = Invoke-ControlMode -Mode "-CC" -Commands @("list-windows", "exit")
$joined = ($output | Out-String)

# Should see %begin and %end framing
$hasBegin = $joined -match "%begin"
$hasEnd = $joined -match "%end"
Add-Result "list-windows has %begin framing" $hasBegin "output: $($joined.Substring(0, [Math]::Min(200, $joined.Length)))"
Add-Result "list-windows has %end framing" $hasEnd

# Should contain window information (at least one window exists)
$hasWindowInfo = $joined -match "0:" -or $joined -match "active"
Add-Result "list-windows returns window data" $hasWindowInfo

# ============================================================
# TEST 2: list-panes output
# ============================================================
Write-Host "`n--- Test 2: list-panes ---" -ForegroundColor Cyan

$output = Invoke-ControlMode -Mode "-CC" -Commands @("list-panes")
$joined = ($output | Out-String)
$hasBegin = $joined -match "%begin"
$hasPaneInfo = $joined -match "%\d+" -or $joined -match "active"
Add-Result "list-panes has %begin framing" $hasBegin
Add-Result "list-panes returns pane data" $hasPaneInfo

# ============================================================
# TEST 3: display-message with format string
# ============================================================
Write-Host "`n--- Test 3: display-message ---" -ForegroundColor Cyan

$output = Invoke-ControlMode -Mode "-CC" -Commands @("display-message -p '#{session_name}'")
$joined = ($output | Out-String)
$hasSessionName = $joined -match $SESSION
Add-Result "display-message shows session name" $hasSessionName "output: $($joined.Substring(0, [Math]::Min(200, $joined.Length)))"

# ============================================================
# TEST 4: new-window and notification
# ============================================================
Write-Host "`n--- Test 4: new-window ---" -ForegroundColor Cyan

$output = Invoke-ControlMode -Mode "-CC" -Commands @("new-window", "list-windows") -TimeoutMs 5000
$joined = ($output | Out-String)

# Should have commands framed
$hasBegin = $joined -match "%begin"
Add-Result "new-window commands are framed" $hasBegin

# list-windows should show at least 2 windows now
$windowLines = $output | Where-Object { $_ -match "^\d+:" }
$multiWindows = $windowLines.Count -ge 2 -or ($joined -match "1:")
Add-Result "new-window creates second window" $multiWindows "windows seen: $($windowLines.Count)"

# ============================================================
# TEST 5: send-keys and capture-pane
# ============================================================
Write-Host "`n--- Test 5: send-keys and capture-pane ---" -ForegroundColor Cyan

$marker = "CTRL_TEST_MARKER_$(Get-Random)"
# First: send keys
$null = Invoke-ControlMode -Mode "-CC" -Commands @(
    "send-keys -t $SESSION 'echo $marker' Enter"
)
# Wait for shell to execute the echo command
Start-Sleep -Seconds 2
# Second: capture pane
$output = Invoke-ControlMode -Mode "-CC" -Commands @(
    "capture-pane -t $SESSION -p"
)
$joined = ($output | Out-String)
$hasMarker = $joined -match $marker
Add-Result "send-keys + capture-pane shows marker" $hasMarker

# ============================================================
# TEST 6: -C mode (echo enabled)
# ============================================================
Write-Host "`n--- Test 6: -C echo mode ---" -ForegroundColor Cyan

$output = Invoke-ControlMode -Mode "-C" -Commands @("list-sessions")
$joined = ($output | Out-String)

# In -C echo mode, the command should be echoed back
$hasEcho = $joined -match "list-sessions"
$hasBegin = $joined -match "%begin"
Add-Result "-C mode echoes commands" $hasEcho
Add-Result "-C mode has %begin framing" $hasBegin

# ============================================================
# TEST 7: -CC mode (no echo)
# ============================================================
Write-Host "`n--- Test 7: -CC no-echo mode ---" -ForegroundColor Cyan

$output = Invoke-ControlMode -Mode "-CC" -Commands @("list-sessions")
$joined = ($output | Out-String)

$hasBegin = $joined -match "%begin"
# In -CC mode, the actual command "list-sessions" should NOT be echoed as a raw line
# But it might appear in the output data. Check that %begin appears before any data.
$lines = $output | Where-Object { $_ -ne "" }
$firstNonEmpty = $lines | Select-Object -First 2
$startsWithProtocol = ($firstNonEmpty | Out-String) -match "^(%|$)" -or ($firstNonEmpty.Count -eq 0)
Add-Result "-CC mode has protocol output" $hasBegin

# ============================================================
# TEST 8: kill-window cleanup
# ============================================================
Write-Host "`n--- Test 8: kill-window ---" -ForegroundColor Cyan

# First count current windows
$beforeOutput = Invoke-ControlMode -Mode "-CC" -Commands @("list-windows")
$beforeLines = $beforeOutput | Where-Object { $_ -match "^\d+:" }
$beforeCount = $beforeLines.Count

# Kill the extra window we created in test 4
$output = Invoke-ControlMode -Mode "-CC" -Commands @("kill-window -t $SESSION`:1", "list-windows")
$joined = ($output | Out-String)
$afterLines = $output | Where-Object { $_ -match "^\d+:" }
$afterCount = $afterLines.Count

$windowKilled = $afterCount -lt $beforeCount -or $afterCount -le 1
Add-Result "kill-window reduces window count" $windowKilled "before=$beforeCount after=$afterCount"

# ============================================================
# TEST 9: Error handling (bad command)
# ============================================================
Write-Host "`n--- Test 9: Error handling ---" -ForegroundColor Cyan

$output = Invoke-ControlMode -Mode "-CC" -Commands @("nonexistent-command-12345")
$joined = ($output | Out-String)
$hasError = $joined -match "%error" -or $joined -match "%end"
Add-Result "Bad command returns %error or %end" $hasError

# ============================================================
# TEST 10: Multiple commands in sequence
# ============================================================
Write-Host "`n--- Test 10: Multiple commands ---" -ForegroundColor Cyan

$output = Invoke-ControlMode -Mode "-CC" -Commands @(
    "list-windows",
    "list-panes",
    "display-message -p '#{window_index}'"
)
$joined = ($output | Out-String)

# Should have multiple %begin/%end pairs
$beginCount = ([regex]::Matches($joined, "%begin")).Count
$endCount = ([regex]::Matches($joined, "%end")).Count + ([regex]::Matches($joined, "%error")).Count

Add-Result "Multiple commands have multiple %begin" ($beginCount -ge 3) "beginCount=$beginCount"
Add-Result "Multiple commands have matching %end" ($endCount -ge 3) "endCount=$endCount"

# ============================================================
# TEST 11: has-session responds correctly
# ============================================================
Write-Host "`n--- Test 11: has-session ---" -ForegroundColor Cyan

$output = Invoke-ControlMode -Mode "-CC" -Commands @("has-session -t $SESSION")
$joined = ($output | Out-String)
$hasEnd = $joined -match "%end"
$noError = -not ($joined -match "%error")
Add-Result "has-session succeeds for existing session" ($hasEnd -and $noError)

# ============================================================
# TEST 12: rename-session
# ============================================================
Write-Host "`n--- Test 12: rename-session ---" -ForegroundColor Cyan

$newName = "ctrl-renamed"
$output = Invoke-ControlMode -Mode "-CC" -Commands @(
    "rename-session $newName",
    "display-message -p '#{session_name}'"
)
$joined = ($output | Out-String)
$hasNewName = $joined -match $newName
Add-Result "rename-session changes name" $hasNewName

# Rename back for cleanup
$env:PSMUX_SESSION_NAME = $newName
$null = Invoke-ControlMode -Mode "-CC" -Commands @("rename-session $SESSION")
Remove-Item env:\PSMUX_SESSION_NAME -ErrorAction SilentlyContinue
$env:PSMUX_SESSION_NAME = $SESSION

# ---- Cleanup ----
Write-Host "`n--- Cleanup ---" -ForegroundColor Yellow
& $exe kill-session -t $SESSION 2>$null
& $exe kill-session -t "ctrl-renamed" 2>$null
Start-Sleep -Milliseconds 500
& $exe kill-server 2>$null
Start-Sleep -Milliseconds 500

# ---- Report ----
Write-Host "`n================================================" -ForegroundColor Cyan
$pass = ($results | Where-Object { $_.Result -eq "PASS" }).Count
$fail = ($results | Where-Object { $_.Result -eq "FAIL" }).Count
$total = $results.Count
Write-Host "Control Mode Tests: Total=$total  Pass=$pass  Fail=$fail" -ForegroundColor $(if($fail -gt 0){"Red"}else{"Green"})
Write-Host "================================================`n" -ForegroundColor Cyan

if ($fail -gt 0) {
    Write-Host "Failed tests:" -ForegroundColor Red
    $results | Where-Object { $_.Result -eq "FAIL" } | ForEach-Object {
        Write-Host "  - $($_.Test) $($_.Detail)" -ForegroundColor Red
    }
    exit 1
} else {
    exit 0
}
