# psmux Issue #60: Mouse scroll not working for native TUI apps (nvim, opencode)
#
# Root cause: inject_mouse_combined used Win32 MOUSE_EVENT records for native
# ConPTY children.  ConPTY does NOT translate MOUSE_EVENT into VT SGR mouse
# sequences, so TUI apps (nvim, opencode, htop) that expect VT mouse input
# never received wheel/click events.
#
# Fix: When a fullscreen TUI app is detected (alternate screen or content
# heuristic), inject SGR mouse as KEY_EVENT records via WriteConsoleInputW,
# the same method already used for VT bridge (ssh/wsl) children.
#
# This test:
#   1. Launches nvim inside a psmux pane
#   2. Verifies fullscreen TUI detection (alternate_on or fullscreen heuristic)
#   3. Verifies mouse-on is set
#   4. Sends scroll events and verifies nvim receives them (no copy mode entry)
#   5. Verifies no escape sequence garbage at shell prompt
#   6. Tests that shell prompt scroll still enters copy mode correctly
#
# Requires: nvim (NVIM v0.11+) installed
# Run: pwsh -NoProfile -ExecutionPolicy Bypass -File tests\test_issue60_native_tui_mouse.ps1

$ErrorActionPreference = "Continue"
$script:TestsPassed = 0
$script:TestsFailed = 0

function Write-Pass { param($msg) Write-Host "[PASS] $msg" -ForegroundColor Green; $script:TestsPassed++ }
function Write-Fail { param($msg) Write-Host "[FAIL] $msg" -ForegroundColor Red; $script:TestsFailed++ }
function Write-Info { param($msg) Write-Host "[INFO] $msg" -ForegroundColor Cyan }
function Write-Test { param($msg) Write-Host "[TEST] $msg" -ForegroundColor White }

# ── Locate psmux binary ──────────────────────────────────────────────────
$PSMUX = (Resolve-Path "$PSScriptRoot\..\target\release\psmux.exe" -ErrorAction SilentlyContinue).Path
if (-not $PSMUX) { $PSMUX = (Resolve-Path "$PSScriptRoot\..\target\debug\psmux.exe" -ErrorAction SilentlyContinue).Path }
if (-not $PSMUX) { Write-Error "psmux binary not found – build first"; exit 1 }
Write-Info "Using: $PSMUX"

# ── Check nvim availability ──────────────────────────────────────────────
$NVIM = (Get-Command nvim -ErrorAction SilentlyContinue).Source
if (-not $NVIM) { Write-Error "nvim not found – install neovim first"; exit 1 }
Write-Info "nvim: $NVIM"
$nvimVer = (& nvim --version | Select-Object -First 1)
Write-Info "nvim version: $nvimVer"

function Psmux { & $PSMUX @args 2>&1; Start-Sleep -Milliseconds 300 }

# ── Clean slate ──────────────────────────────────────────────────────────
Write-Info "Cleaning up old sessions..."
Start-Process -FilePath $PSMUX -ArgumentList "kill-server" -WindowStyle Hidden
Start-Sleep -Seconds 3
Remove-Item "$env:USERPROFILE\.psmux\*.port" -Force -ErrorAction SilentlyContinue
Remove-Item "$env:USERPROFILE\.psmux\*.key" -Force -ErrorAction SilentlyContinue
# Clear mouse debug log
Remove-Item "$env:USERPROFILE\.psmux\mouse_debug.log" -Force -ErrorAction SilentlyContinue

$SESSION = "issue60test"

# ── Enable mouse debug logging ──────────────────────────────────────────
$env:PSMUX_MOUSE_DEBUG = "1"

# ── Create session ───────────────────────────────────────────────────────
Write-Info "Creating session '$SESSION'..."
Start-Process -FilePath $PSMUX -ArgumentList "new-session -s $SESSION -d" -WindowStyle Hidden
Start-Sleep -Seconds 4

& $PSMUX has-session -t $SESSION 2>$null
if ($LASTEXITCODE -ne 0) { Write-Host "FATAL: Cannot create session" -ForegroundColor Red; exit 1 }
Write-Info "Session created"

# ── Ensure mouse is on ──────────────────────────────────────────────────
Psmux set-option -g mouse on
$mouseOpt = (Psmux display-message -t $SESSION -p "#{mouse}")
Write-Info "mouse option: $mouseOpt"

# ══════════════════════════════════════════════════════════════════════════
# PART 1: Shell prompt baseline — verify scroll enters copy mode
# ══════════════════════════════════════════════════════════════════════════
Write-Host ""
Write-Host ("=" * 60) -ForegroundColor Yellow
Write-Host "PART 1: SHELL PROMPT SCROLL (baseline)" -ForegroundColor Yellow
Write-Host ("=" * 60) -ForegroundColor Yellow

Write-Test "1.1 mouse option is on"
if ($mouseOpt -match "on") { Write-Pass "mouse is on" } else { Write-Fail "mouse not on: '$mouseOpt'" }

Write-Test "1.2 shell prompt: alternate_on should be 0"
$altOn = (Psmux display-message -t $SESSION -p "#{alternate_on}")
Write-Info "alternate_on at shell: $altOn"
if ($altOn -match "0") { Write-Pass "alternate_on=0 at shell prompt" } else { Write-Fail "alternate_on=$altOn (expected 0)" }

Write-Test "1.3 shell prompt: not in copy mode initially"
$modeFlag = (Psmux display-message -t $SESSION -p "#{pane_in_mode}")
if ($modeFlag -match "0") { Write-Pass "Not in copy mode" } else { Write-Fail "Unexpected mode: $modeFlag" }

# Generate some scrollback so scroll-up has content
for ($i = 0; $i -lt 30; $i++) { Psmux send-keys -t $SESSION "echo scrollback_line_$i" Enter }
Start-Sleep -Milliseconds 500

Write-Test "1.4 shell prompt: copy-mode CLI entry works"
Psmux copy-mode -t $SESSION
Start-Sleep -Milliseconds 500
$modeFlag = (Psmux display-message -t $SESSION -p "#{pane_in_mode}")
if ($modeFlag -match "1") { Write-Pass "copy-mode entered at shell prompt" } else { Write-Fail "copy-mode not entered: $modeFlag" }
Psmux send-keys -t $SESSION q
Start-Sleep -Milliseconds 300
$modeFlag = (Psmux display-message -t $SESSION -p "#{pane_in_mode}")
if ($modeFlag -match "0") { Write-Pass "copy-mode exited" } else { Write-Fail "copy-mode not exited: $modeFlag" }

# ══════════════════════════════════════════════════════════════════════════
# PART 2: Launch nvim — fullscreen TUI detection
# ══════════════════════════════════════════════════════════════════════════
Write-Host ""
Write-Host ("=" * 60) -ForegroundColor Yellow
Write-Host "PART 2: NVIM FULLSCREEN TUI DETECTION" -ForegroundColor Yellow
Write-Host ("=" * 60) -ForegroundColor Yellow

# Create a temp file for nvim to edit
$tempFile = [System.IO.Path]::GetTempFileName() + ".txt"
# Write many lines so nvim has content to scroll
$lines = @()
for ($i = 1; $i -le 200; $i++) { $lines += "Line ${i}: The quick brown fox jumps over the lazy dog." }
$lines | Set-Content -Path $tempFile -Encoding UTF8

Write-Test "2.1 Launching nvim in psmux pane..."
Psmux send-keys -t $SESSION "nvim --clean `"$tempFile`"" Enter
# Wait for nvim to start and render
Start-Sleep -Seconds 4

Write-Test "2.2 fullscreen TUI detection (alternate_on or fullscreen heuristic)"
# Check alternate_on — nvim uses alternate screen buffer
$altOn = (Psmux display-message -t $SESSION -p "#{alternate_on}")
Write-Info "alternate_on with nvim: $altOn"

# Also check the pane content — nvim should fill the screen
$capture = (Psmux capture-pane -t $SESSION -p) | Out-String
$nvimRunning = ($capture -match "Line 1:" -or $capture -match "NVIM" -or $capture -match "\.txt")
Write-Info "nvim content detected: $nvimRunning"
if ($altOn -match "1" -or $nvimRunning) {
    Write-Pass "Fullscreen TUI detected (alternate_on=$altOn, content=$nvimRunning)"
} else {
    Write-Fail "Fullscreen TUI NOT detected (alternate_on=$altOn, content=$nvimRunning)"
}

Write-Test "2.3 nvim should NOT be in psmux copy mode"
$modeFlag = (Psmux display-message -t $SESSION -p "#{pane_in_mode}")
if ($modeFlag -match "0") { Write-Pass "Not in copy mode (nvim handles its own)" } else { Write-Fail "Unexpected copy mode: $modeFlag" }

# ══════════════════════════════════════════════════════════════════════════
# PART 3: Mouse event injection — verify SGR path for native ConPTY TUI
# ══════════════════════════════════════════════════════════════════════════
Write-Host ""
Write-Host ("=" * 60) -ForegroundColor Yellow
Write-Host "PART 3: MOUSE EVENT INJECTION (Issue #60 core test)" -ForegroundColor Yellow
Write-Host ("=" * 60) -ForegroundColor Yellow

# Read the port and key for the TCP protocol
$portFile = Get-ChildItem "$env:USERPROFILE\.psmux\*.port" | Select-Object -First 1
$keyFile  = Get-ChildItem "$env:USERPROFILE\.psmux\*.key"  | Select-Object -First 1
if (-not $portFile -or -not $keyFile) {
    Write-Fail "Cannot find psmux port/key files for TCP protocol"
} else {
    $port = Get-Content $portFile.FullName -Raw | ForEach-Object { $_.Trim() }
    $key  = Get-Content $keyFile.FullName -Raw | ForEach-Object { $_.Trim() }
    Write-Info "TCP protocol: port=$port"

    function Send-PsmuxCmd {
        param([string]$Cmd)
        try {
            $tcp = New-Object System.Net.Sockets.TcpClient("127.0.0.1", $port)
            $stream = $tcp.GetStream()
            $writer = New-Object System.IO.StreamWriter($stream)
            $reader = New-Object System.IO.StreamReader($stream)
            $writer.AutoFlush = $true
            $writer.WriteLine("AUTH $key")
            Start-Sleep -Milliseconds 100
            $authResp = $reader.ReadLine()
            $writer.WriteLine($Cmd)
            Start-Sleep -Milliseconds 50
            $tcp.Close()
            return $authResp
        } catch {
            return "ERROR: $_"
        }
    }

    # Capture nvim content BEFORE scroll
    $beforeCapture = (Psmux capture-pane -t $SESSION -p) | Out-String

    Write-Test "3.1 Send scroll-down events to nvim pane"
    # Send multiple scroll-down events — nvim should scroll its buffer
    for ($i = 0; $i -lt 10; $i++) {
        Send-PsmuxCmd "mouse-scroll-down 20 15"
        Start-Sleep -Milliseconds 100
    }
    Start-Sleep -Seconds 1

    Write-Test "3.2 Verify psmux did NOT enter copy mode (scroll forwarded to nvim)"
    $modeFlag = (Psmux display-message -t $SESSION -p "#{pane_in_mode}")
    if ($modeFlag -match "0") {
        Write-Pass "Not in copy mode — scroll forwarded to nvim (not intercepted by psmux)"
    } else {
        Write-Fail "psmux entered copy mode instead of forwarding scroll to nvim: mode=$modeFlag"
    }

    # Capture nvim content AFTER scroll
    $afterCapture = (Psmux capture-pane -t $SESSION -p) | Out-String

    Write-Test "3.3 Check capture for signs nvim received scroll"
    # If nvim scrolled, the first visible line should have changed
    # Before: "Line 1: ..." should be near top
    # After: Higher numbered lines should be visible
    $beforeHasLine1 = $beforeCapture -match "Line 1:"
    $afterHasLine1  = $afterCapture -match "Line 1:"
    Write-Info "Before scroll has 'Line 1:': $beforeHasLine1"
    Write-Info "After scroll has 'Line 1:': $afterHasLine1"

    # Check for higher-numbered lines after scrolling
    $afterHasHigherLines = $afterCapture -match "Line [2-9][0-9]:"
    Write-Info "After scroll has higher-numbered lines: $afterHasHigherLines"

    if (-not $afterHasLine1 -and $afterHasHigherLines) {
        Write-Pass "nvim scrolled: Line 1 no longer visible, higher lines shown"
    } elseif ($afterHasHigherLines) {
        Write-Pass "nvim shows higher-numbered lines (scroll likely worked)"
    } else {
        Write-Info "Before capture (first 5 lines): $(($beforeCapture -split "`n" | Select-Object -First 5) -join ' | ')"
        Write-Info "After capture (first 5 lines): $(($afterCapture -split "`n" | Select-Object -First 5) -join ' | ')"
        Write-Fail "Cannot confirm nvim received scroll events (content unchanged)"
    }

    Write-Test "3.4 No escape sequence garbage in nvim pane"
    $sgrPattern = '\[<\d+;\d+;\d+[Mm]'
    if ($afterCapture -match $sgrPattern) {
        Write-Fail "SGR mouse escape sequences visible in nvim capture"
    } else {
        Write-Pass "No escape sequence garbage"
    }

    Write-Test "3.5 Send scroll-up events to nvim pane"
    for ($i = 0; $i -lt 10; $i++) {
        Send-PsmuxCmd "mouse-scroll-up 20 15"
        Start-Sleep -Milliseconds 100
    }
    Start-Sleep -Seconds 1

    $scrollUpCapture = (Psmux capture-pane -t $SESSION -p) | Out-String
    Write-Test "3.6 Verify psmux still NOT in copy mode after scroll-up in nvim"
    $modeFlag = (Psmux display-message -t $SESSION -p "#{pane_in_mode}")
    if ($modeFlag -match "0") {
        Write-Pass "Not in copy mode after scroll-up — forwarded to nvim"
    } else {
        Write-Fail "psmux entered copy mode on scroll-up in nvim: mode=$modeFlag"
        # Exit copy mode to continue testing
        Psmux send-keys -t $SESSION q
        Start-Sleep -Milliseconds 300
    }

    Write-Test "3.7 Send left-click to nvim (cursor positioning)"
    Send-PsmuxCmd "mouse-down 10 5"
    Start-Sleep -Milliseconds 100
    Send-PsmuxCmd "mouse-up 10 5"
    Start-Sleep -Milliseconds 300

    # nvim should still be running, not crashed
    $clickCapture = (Psmux capture-pane -t $SESSION -p) | Out-String
    $nvimStillRunning = ($clickCapture -match "Line \d+:" -or $clickCapture -match "NVIM")
    if ($nvimStillRunning) {
        Write-Pass "nvim still running after mouse click"
    } else {
        Write-Fail "nvim may have crashed after mouse click"
    }
}

# ══════════════════════════════════════════════════════════════════════════
# PART 4: Check mouse debug log for SGR injection evidence
# ══════════════════════════════════════════════════════════════════════════
Write-Host ""
Write-Host ("=" * 60) -ForegroundColor Yellow
Write-Host "PART 4: MOUSE DEBUG LOG ANALYSIS" -ForegroundColor Yellow
Write-Host ("=" * 60) -ForegroundColor Yellow

$debugLogPath = "$env:USERPROFILE\.psmux\mouse_debug.log"
if (Test-Path $debugLogPath) {
    $debugLog = Get-Content $debugLogPath -Raw
    Write-Info "Mouse debug log size: $((Get-Item $debugLogPath).Length) bytes"

    Write-Test "4.1 Debug log contains scroll forwarding entries"
    if ($debugLog -match "forwarding scroll to child TUI") {
        Write-Pass "Found 'forwarding scroll to child TUI' in debug log"
    } else {
        Write-Fail "No scroll forwarding entries in debug log"
    }

    Write-Test "4.2 Debug log contains SGR VT injection for fullscreen TUI"
    # After fix: should see "SGR VT injection" or "Console VT injection" for native ConPTY
    if ($debugLog -match "Console VT injection.*KEY_EVENT") {
        Write-Pass "Found SGR VT injection via KEY_EVENTs in debug log (fix working!)"
    } elseif ($debugLog -match "SGR VT injection") {
        Write-Pass "Found SGR VT injection in debug log (fix working!)"
    } else {
        Write-Info "Debug log content (last 20 lines):"
        $debugLog -split "`n" | Select-Object -Last 20 | ForEach-Object { Write-Info "  $_" }
        Write-Fail "No SGR VT injection found — still using Win32 MOUSE_EVENT for native TUI?"
    }

    Write-Test "4.3 Debug log does NOT show Win32 MOUSE_EVENT for fullscreen TUI"
    # After fix: for fullscreen TUI apps, should NOT see "Win32 MOUSE_EVENT (native ConPTY)"
    # (it's OK if we see it for shell prompt)
    $win32ForNative = ($debugLog -split "`n" | Where-Object { $_ -match "Win32 MOUSE_EVENT \(native ConPTY\)" })
    # Filter: only look at entries AFTER nvim started (heuristic: after alt_screen=true)
    $afterNvim = $false
    $win32DuringTui = @()
    foreach ($line in ($debugLog -split "`n")) {
        if ($line -match "fullscreen=true" -or $line -match "alt_screen=true") { $afterNvim = $true }
        if ($afterNvim -and $line -match "Win32 MOUSE_EVENT \(native ConPTY\)") {
            $win32DuringTui += $line
        }
    }
    if ($win32DuringTui.Count -eq 0) {
        Write-Pass "No Win32 MOUSE_EVENT for native ConPTY during fullscreen TUI"
    } else {
        Write-Fail "Found Win32 MOUSE_EVENT during fullscreen TUI ($($win32DuringTui.Count) occurrences)"
        $win32DuringTui | Select-Object -First 3 | ForEach-Object { Write-Info "  $_" }
    }
} else {
    Write-Info "Mouse debug log not found at $debugLogPath"
    Write-Info "Set PSMUX_MOUSE_DEBUG=1 before running psmux to enable debug logging"
    Write-Info "[SKIP] Cannot verify injection method without debug log"
}

# ══════════════════════════════════════════════════════════════════════════
# PART 5: Exit nvim and verify shell prompt scroll behavior
# ══════════════════════════════════════════════════════════════════════════
Write-Host ""
Write-Host ("=" * 60) -ForegroundColor Yellow
Write-Host "PART 5: POST-NVIM SHELL PROMPT VERIFICATION" -ForegroundColor Yellow
Write-Host ("=" * 60) -ForegroundColor Yellow

Write-Test "5.1 Exit nvim gracefully"
Psmux send-keys -t $SESSION Escape
Start-Sleep -Milliseconds 200
Psmux send-keys -t $SESSION ":q!" Enter
Start-Sleep -Seconds 2

$capture = (Psmux capture-pane -t $SESSION -p) | Out-String
Write-Info "Post-nvim capture (first 3 lines): $(($capture -split "`n" | Where-Object { $_.Trim() } | Select-Object -First 3) -join ' | ')"

Write-Test "5.2 Back at shell prompt (alternate_on=0)"
$altOn = (Psmux display-message -t $SESSION -p "#{alternate_on}")
Write-Info "alternate_on after nvim exit: $altOn"
if ($altOn -match "0") { Write-Pass "Back to normal screen" } else { Write-Fail "Still in alt screen: $altOn" }

Write-Test "5.3 Shell prompt: no escape sequence garbage"
$sgrPattern = '\[<\d+;\d+;\d+[Mm]'
if ($capture -match $sgrPattern) {
    Write-Fail "SGR mouse sequences visible at shell prompt"
} else {
    Write-Pass "Clean shell prompt"
}

Write-Test "5.4 Shell prompt: copy-mode still works"
Psmux copy-mode -t $SESSION
Start-Sleep -Milliseconds 500
$modeFlag = (Psmux display-message -t $SESSION -p "#{pane_in_mode}")
if ($modeFlag -match "1") { Write-Pass "Copy mode works at shell prompt" } else { Write-Fail "Copy mode broken: $modeFlag" }
Psmux send-keys -t $SESSION q
Start-Sleep -Milliseconds 300

# ══════════════════════════════════════════════════════════════════════════
# PART 6: Split pane — verify mouse works across panes with TUI
# ══════════════════════════════════════════════════════════════════════════
Write-Host ""
Write-Host ("=" * 60) -ForegroundColor Yellow
Write-Host "PART 6: SPLIT PANE TUI MOUSE (multi-pane scenario)" -ForegroundColor Yellow
Write-Host ("=" * 60) -ForegroundColor Yellow

Write-Test "6.1 Create horizontal split"
Psmux split-window -t $SESSION -h
Start-Sleep -Seconds 2

$paneCount = (Psmux list-panes -t $SESSION 2>&1 | Measure-Object -Line).Lines
Write-Info "Pane count: $paneCount"
if ($paneCount -ge 2) { Write-Pass "Split created ($paneCount panes)" } else { Write-Fail "Split failed: $paneCount panes" }

Write-Test "6.2 Launch nvim in second pane"
$tempFile2 = [System.IO.Path]::GetTempFileName() + ".txt"
$lines2 = @()
for ($i = 1; $i -le 100; $i++) { $lines2 += "Pane2 Line ${i}: Lorem ipsum dolor sit amet." }
$lines2 | Set-Content -Path $tempFile2 -Encoding UTF8
Psmux send-keys -t $SESSION "nvim --clean `"$tempFile2`"" Enter
Start-Sleep -Seconds 3

Write-Test "6.3 Session still alive with split + nvim"
& $PSMUX has-session -t $SESSION 2>$null
if ($LASTEXITCODE -eq 0) { Write-Pass "Session alive with split + nvim" } else { Write-Fail "Session died" }

# Exit nvim in second pane
Psmux send-keys -t $SESSION Escape
Start-Sleep -Milliseconds 200
Psmux send-keys -t $SESSION ":q!" Enter
Start-Sleep -Seconds 1

# ══════════════════════════════════════════════════════════════════════════
# CLEANUP
# ══════════════════════════════════════════════════════════════════════════
Write-Host ""
Write-Host ("=" * 60) -ForegroundColor Yellow
Write-Host "CLEANUP" -ForegroundColor Yellow
Write-Host ("=" * 60) -ForegroundColor Yellow

Psmux kill-session -t $SESSION
Start-Sleep -Seconds 1
Remove-Item $tempFile -Force -ErrorAction SilentlyContinue
Remove-Item $tempFile2 -Force -ErrorAction SilentlyContinue

# ══════════════════════════════════════════════════════════════════════════
# SUMMARY
# ══════════════════════════════════════════════════════════════════════════
Write-Host ""
Write-Host ("=" * 60) -ForegroundColor Magenta
Write-Host "ISSUE #60 TEST RESULTS" -ForegroundColor Magenta
Write-Host ("=" * 60) -ForegroundColor Magenta
Write-Host "Passed: $($script:TestsPassed)" -ForegroundColor Green
Write-Host "Failed: $($script:TestsFailed)" -ForegroundColor $(if ($script:TestsFailed -gt 0) { "Red" } else { "Green" })
$total = $script:TestsPassed + $script:TestsFailed
Write-Host "Total:  $total"
Write-Host ""
if ($script:TestsFailed -eq 0) {
    Write-Host "ALL TESTS PASSED — Issue #60 fix verified!" -ForegroundColor Green
} else {
    Write-Host "$($script:TestsFailed) test(s) failed" -ForegroundColor Red
}

exit $script:TestsFailed
