if ($operation -ne 'rg') { Fail ('unsupported Windows fs operation: ' + $operation) 2 }

$ignoreCase = $false; $fixed = $false; $filesOnly = $false; $endOptions = $false
$maxCount = [int]$rgPolicy.maxMatches; $maxFiles = [int]$rgPolicy.maxFiles; $maxBytes = [int]$rgPolicy.maxBytesPerFile; $timeoutMs = [int]$rgPolicy.timeoutMs
$paths = [Collections.Generic.List[string]]::new(); $globs = [Collections.Generic.List[string]]::new(); $patterns = [Collections.Generic.List[string]]::new()
for ($i = 0; $i -lt $toolArgs.Count; $i++) {
  $arg = $toolArgs[$i]
  if (-not $endOptions -and $arg -eq '--') { $endOptions = $true; continue }
  if (-not $endOptions -and $arg -in @('-i', '--ignore-case')) { $ignoreCase = $true; continue }
  if (-not $endOptions -and $arg -in @('-F', '--fixed-strings')) { $fixed = $true; continue }
  if (-not $endOptions -and $arg -in @('-n', '--line-number')) { continue }
  if (-not $endOptions -and $arg -eq '--files') { $filesOnly = $true; continue }
  if (-not $endOptions -and $arg -in @('-e', '--regexp')) { $i += 1; if ($i -ge $toolArgs.Count) { Fail ($arg + ' requires a value') 2 }; $patterns.Add($toolArgs[$i]); continue }
  if (-not $endOptions -and $arg.StartsWith('--regexp=')) { $patterns.Add($arg.Substring(9)); continue }
  if (-not $endOptions -and $arg -in @('-g', '--glob')) { $i += 1; if ($i -ge $toolArgs.Count) { Fail ($arg + ' requires a value') 2 }; $globs.Add($toolArgs[$i]); continue }
  if (-not $endOptions -and $arg.StartsWith('--glob=')) { $globs.Add($arg.Substring(7)); continue }
  if (-not $endOptions -and $arg -in @('-m', '--max-count')) { $i += 1; if ($i -ge $toolArgs.Count) { Fail ($arg + ' requires a value') 2 }; $maxCount = Parse-NonNegativeInt $arg $toolArgs[$i] 10000; continue }
  if (-not $endOptions -and $arg.StartsWith('-m') -and $arg.Length -gt 2) { $maxCount = Parse-NonNegativeInt '-m' $arg.Substring(2) 10000; continue }
  if (-not $endOptions -and $arg.StartsWith('--max-count=')) { $maxCount = Parse-NonNegativeInt '--max-count' $arg.Substring(12) 10000; continue }
  if (-not $endOptions -and $arg -eq '--max-files') { $i += 1; if ($i -ge $toolArgs.Count) { Fail '--max-files requires a value' 2 }; $maxFiles = Parse-NonNegativeInt '--max-files' $toolArgs[$i] 50000; continue }
  if (-not $endOptions -and $arg.StartsWith('--max-files=')) { $maxFiles = Parse-NonNegativeInt '--max-files' $arg.Substring(12) 50000; continue }
  if (-not $endOptions -and $arg -eq '--max-bytes') { $i += 1; if ($i -ge $toolArgs.Count) { Fail '--max-bytes requires a value' 2 }; $maxBytes = Parse-NonNegativeInt '--max-bytes' $toolArgs[$i] 16777216; continue }
  if (-not $endOptions -and $arg.StartsWith('--max-bytes=')) { $maxBytes = Parse-NonNegativeInt '--max-bytes' $arg.Substring(12) 16777216; continue }
  if (-not $endOptions -and $arg -eq '--timeout-ms') { $i += 1; if ($i -ge $toolArgs.Count) { Fail '--timeout-ms requires a value' 2 }; $timeoutMs = Parse-NonNegativeInt '--timeout-ms' $toolArgs[$i] 60000; continue }
  if (-not $endOptions -and $arg.StartsWith('--timeout-ms=')) { $timeoutMs = Parse-NonNegativeInt '--timeout-ms' $arg.Substring(13) 60000; continue }
  if (-not $endOptions -and $arg.StartsWith('-')) { Fail ('unsupported rg option on Windows route: ' + $arg + '; supported: --files -e/--regexp -g/--glob -i -F -n -m/--max-count --max-files --max-bytes --timeout-ms') 2 }
  if ($filesOnly) { $paths.Add($arg) } elseif ($patterns.Count -eq 0) { $patterns.Add($arg) } else { $paths.Add($arg) }
}
if (-not $filesOnly -and $patterns.Count -eq 0) { Fail 'rg requires a pattern on Windows routes (or use --files)' 2 }
if ($paths.Count -eq 0) { $paths.Add('.') }

$nativeRg = Get-Command rg.exe -ErrorAction SilentlyContinue | Select-Object -First 1
if ($null -eq $nativeRg) { Fail 'rg.exe is unavailable on this Windows plane; install ripgrep or use ps with a reviewed PowerShell search' 127 }
if ($null -ne $nativeRg) {
  function Quote-NativeArg([string]$Value) {
    if ($Value.Contains('"')) { Fail 'rg argument contains a quote; use ps for shell-reviewed quoting' 2 }
    if ($Value -match '\s') { return '"' + $Value + '"' }
    return $Value
  }
  $nativeArgs = [Collections.Generic.List[string]]::new()
  $nativeArgs.Add('--color=never'); $nativeArgs.Add('--no-heading'); $nativeArgs.Add('--line-number'); $nativeArgs.Add('--with-filename')
  $nativeArgs.Add('--max-filesize'); $nativeArgs.Add([string]$maxBytes)
  if ($ignoreCase) { $nativeArgs.Add('--ignore-case') }
  if ($fixed) { $nativeArgs.Add('--fixed-strings') }
  foreach ($glob in $globs) { $nativeArgs.Add('--glob'); $nativeArgs.Add($glob) }
  if ($filesOnly) { $nativeArgs.Add('--files') } else { foreach ($item in $patterns) { $nativeArgs.Add('--regexp'); $nativeArgs.Add($item) } }
  foreach ($raw in $paths) { $nativeArgs.Add((Resolve-UnideskPath $raw)) }
  $startInfo = [Diagnostics.ProcessStartInfo]::new()
  $startInfo.FileName = $nativeRg.Source
  $startInfo.Arguments = [string]::Join(' ', @($nativeArgs | ForEach-Object { Quote-NativeArg $_ }))
  $startInfo.UseShellExecute = $false; $startInfo.CreateNoWindow = $true; $startInfo.RedirectStandardOutput = $true; $startInfo.RedirectStandardError = $true
  $process = [Diagnostics.Process]::new(); $process.StartInfo = $startInfo
  $stopwatch = [Diagnostics.Stopwatch]::StartNew()
  if (-not $process.Start()) { Fail 'failed to start native rg.exe' 2 }
  $stdoutTask = $process.StandardOutput.ReadToEndAsync(); $stderrTask = $process.StandardError.ReadToEndAsync()
  $timedOut = -not $process.WaitForExit($timeoutMs)
  if ($timedOut) { try { $process.Kill() } catch {}; $process.WaitForExit() }
  $stdoutText = $stdoutTask.Result; $stderrText = $stderrTask.Result; $stopwatch.Stop()
  $lines = Text-Lines $stdoutText; $outputLimit = if ($filesOnly) { $maxFiles } else { $maxCount }; $selected = [string[]]($lines | Select-Object -First $outputLimit)
  Print-Lines $selected
  if (-not [string]::IsNullOrWhiteSpace($stderrText)) { [Console]::Error.Write($stderrText) }
  $truncated = $lines.Count -gt $selected.Count
  $matchedFiles = [Collections.Generic.HashSet[string]]::new([StringComparer]::OrdinalIgnoreCase)
  if (-not $filesOnly) { foreach ($line in $selected) { if ($line -match '^(.+?):\d+:') { [void]$matchedFiles.Add($Matches[1]) } } }
  $fileCount = if ($filesOnly) { $selected.Count } else { $matchedFiles.Count }
  $encodingState = if ($stdoutText.Contains([char]0xfffd)) { 'legacy-or-invalid-utf8' } else { 'utf8-or-ascii' }
  [Console]::Error.WriteLine('UNIDESK_WINDOWS_RG_SUMMARY matched=' + $selected.Count + ' fileCount=' + $fileCount + ' elapsedMs=' + $stopwatch.ElapsedMilliseconds + ' timeout=' + $timedOut.ToString().ToLowerInvariant() + ' encoding=' + $encodingState + ' skipped=0 fileLimit=' + ($filesOnly -and $truncated).ToString().ToLowerInvariant() + ' matchLimit=' + ((-not $filesOnly) -and $truncated).ToString().ToLowerInvariant() + ' engine=native-rg config=config/unidesk-cli.yaml#trans.windowsFs.rg')
  if ($timedOut) { [Console]::Error.WriteLine('UNIDESK_WINDOWS_RG_HINT code=timeout exitCode=124 action=narrow-scope-or-add-glob message=retry-with-a-narrower-path-or-g/--glob'); exit 124 }
  if ($process.ExitCode -ne 0) { exit $process.ExitCode }
  exit 0
}
