<#
  Собрать один файл с диагностикой и положить на рабочий стол.

  Нужен, когда программа ведёт себя не так на чужом компьютере: вместо
  пересказа «сбрасывается примерно на пятом шаге» приходит журнал, где видно
  и шаг, и причину. Пароли и ключи в отчёт не попадают.

  Запуск: правой кнопкой по файлу -> «Выполнить с помощью PowerShell»,
  либо из программы кнопкой «Собрать отчёт».
#>
$ErrorActionPreference = "Continue"
try { chcp 65001 | Out-Null } catch {}

$home_ = $env:CLAUDE_PROXY_HOME
if (-not $home_) { $home_ = Join-Path $env:USERPROFILE ".claude-proxy-control" }
$merged = Join-Path $home_ "merged"
$out = Join-Path ([Environment]::GetFolderPath("Desktop")) ("cpc-report-" + (Get-Date -Format "yyyyMMdd-HHmmss") + ".txt")

function Section([string]$title) {
  Add-Content $out ""
  Add-Content $out ("=" * 70)
  Add-Content $out ("  " + $title)
  Add-Content $out ("=" * 70)
}

function Hide-Secrets([string]$text) {
  # Пароль прокси и ключ лицензии наружу не отдаём.
  if (-not $text) { return $text }
  $text = $text -replace '(?i)(PROXY_PASS\s*=\s*).*', '$1***'
  $text = $text -replace '(?i)("password"\s*:\s*")[^"]*', '$1***'
  $text = $text -replace '(?i)(access_token"\s*:\s*")[^"]*', '$1***'
  $text = $text -replace '(CPC-[A-Z0-9]{6})-[A-Z0-9]{6}', '$1-******'
  return $text
}

function Tail([string]$path, [int]$lines = 120) {
  if (-not (Test-Path $path)) { Add-Content $out ("нет файла: " + $path); return }
  $info = Get-Item $path
  Add-Content $out ("файл: " + $path + "  (" + [math]::Round($info.Length / 1KB) + " КБ, изменён " + $info.LastWriteTime + ")")
  Add-Content $out "-----"
  $text = (Get-Content $path -Tail $lines -Encoding UTF8) -join "`r`n"
  Add-Content $out (Hide-Secrets $text)
}

Set-Content $out ("Claude Proxy Control - отчёт " + (Get-Date -Format "yyyy-MM-dd HH:mm:ss")) -Encoding UTF8

Section "Версия программы"
# Первым делом: без этого разговор о любой ошибке начинается с угадывания,
# какая сборка стоит у человека.
$verFile = Join-Path $home_ "VERSION"
Add-Content $out ("версия: " + $(if (Test-Path $verFile) { (Get-Content $verFile -Raw).Trim() } else { "НЕ УКАЗАНА (сборка старше 1.0.0)" }))
$buildFile = Join-Path $home_ "BUILD.txt"
if (Test-Path $buildFile) { Get-Content $buildFile | ForEach-Object { Add-Content $out ("  " + $_) } }

Section "Система"
Add-Content $out ("Windows: " + (Get-CimInstance Win32_OperatingSystem).Caption + " " + [Environment]::OSVersion.Version)
Add-Content $out ("Компьютер: " + $env:COMPUTERNAME + " | пользователь: " + $env:USERNAME)
Add-Content $out ("Папка продукта: " + $home_)
Add-Content $out ("Админ: " + ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator))

Section "Что установлено"
foreach ($f in @("license.json", "proxy.env", "settings.json", "python-path.txt", "desktop-path.txt")) {
  $p = Join-Path $home_ $f
  Add-Content $out (("{0,-20} {1}" -f $f, $(if (Test-Path $p) { "есть" } else { "НЕТ" })))
}
$sb = Get-ChildItem (Join-Path $home_ "sing-box") -Directory -Filter "sing-box-*" -ErrorAction SilentlyContinue
Add-Content $out ("sing-box: " + $(if ($sb) { $sb[0].Name } else { "НЕ НАЙДЕН" }))
Add-Content $out ("сборщик: " + $(if (Test-Path (Join-Path $merged "build_sota_merged_config.py")) { "есть" } else { "НЕТ" }))

Section "Сеть и процессы"
Get-NetAdapter -ErrorAction SilentlyContinue | Where-Object { $_.Status -eq "Up" } |
  ForEach-Object { Add-Content $out ("адаптер UP: " + $_.Name + " | " + $_.InterfaceDescription) }
Get-CimInstance Win32_Process -Filter "Name='sing-box.exe'" -ErrorAction SilentlyContinue |
  ForEach-Object { Add-Content $out ("sing-box pid " + $_.ProcessId + " -> " + $_.ExecutablePath) }
Add-Content $out ("правило брандмауэра kill-switch: " + $(if (Get-NetFirewallRule -DisplayName "CPC-KillSwitch-TunRebuild" -ErrorAction SilentlyContinue) { "СТОИТ (это плохо в покое)" } else { "нет" }))
foreach ($t in @("CPC-SotaCaptureWatcher", "CPC-NetMonitor")) {
  $task = Get-ScheduledTask -TaskName $t -ErrorAction SilentlyContinue
  Add-Content $out ("задание " + $t + ": " + $(if ($task) { $task.State } else { "НЕТ" }))
}

Section "Журнал установки ловца узлов - последние 60 строк"
Tail (Join-Path $home_ "logs\watcher-install.log") 60

Section "Журнал установки (cpc-install.log) - последние 120 строк"
# Установка идёт в отдельном окне с правами администратора, и при ошибке это
# окно закрывается быстрее, чем человек успевает прочитать. Лог остаётся здесь.
Tail (Join-Path $env:TEMP "cpc-install.log") 120

Section "Предыдущая попытка установки (cpc-install.prev.log) - последние 60 строк"
# Интересна как раз она: неудачную попытку человек обычно повторяет, и без
# этого файла её след затирался успешной второй.
Tail (Join-Path $env:TEMP "cpc-install.prev.log") 60

Section "Ярлыки"
$desk = [Environment]::GetFolderPath("Desktop")
$lnk = Join-Path $desk "Claude Proxy Control.lnk"
Add-Content $out ("рабочий стол: " + $desk)
Add-Content $out ("ярлык: " + $(if (Test-Path $lnk) { "есть" } else { "НЕТ" }))

Section "Ход последнего запуска (start-progress.json)"
Tail (Join-Path $merged "start-progress.json") 60

Section "Журнал запуска (last-start.log) - последние 200 строк"
Tail (Join-Path $home_ "logs\last-start.log") 200
Tail (Join-Path $merged "last-start.log") 200

Section "Трассировка программы (cpc-trace.log) - последние 150 строк"
Tail (Join-Path $home_ "logs\cpc-trace.log") 150

Section "Журнал туннеля (vpn-claude-tun.log) - последние 80 строк"
Tail (Join-Path $merged "vpn-claude-tun.log") 80

Section "Статус и проверки"
Tail (Join-Path $merged "status.json") 40
Tail (Join-Path $merged "monitor-last.json") 40
Tail (Join-Path $merged "squid-live.json") 10

Section "Каналы приложений"
Tail (Join-Path $merged "app-rules.json") 80

Write-Host ""
Write-Host "Отчёт готов:" -ForegroundColor Green
Write-Host ("  " + $out) -ForegroundColor White
Write-Host ""
Write-Host "Пароли и ключи из него вырезаны. Отправьте этот файл в поддержку." -ForegroundColor Gray
try { explorer.exe "/select,`"$out`"" } catch {}
if (-not $env:CLAUDE_PROXY_NOPAUSE) { Pause }
