<#
.SYNOPSIS
  Комендант MDM - ADB Device Enrollment Tool
.DESCRIPTION
  Регистрирует Android устройство в MDM через USB-кабель без QR-кода.
  Обходит Play Protect DPC allowlist и Samsung-ограничения.
.PARAMETER Link
  Enrollment ссылка формата komendant://enroll?code=X&server=Y&mqtt=Z&token=W
.PARAMETER NonInteractive
  Не ждать нажатия клавиш (для CI-теста)
.EXAMPLE
  .\enroll.ps1 -Link "komendant://enroll?code=..."
#>
param(
    [string]$Link = "",
    [switch]$NonInteractive
)

$ErrorActionPreference = 'Stop'
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
$OutputEncoding = [System.Text.Encoding]::UTF8

$root = Split-Path -Parent $PSCommandPath
$adb  = Join-Path $root 'adb.exe'
$apk  = Join-Path $root 'komendant-dpc.apk'

function Pause-Script { if (-not $NonInteractive) { Read-Host 'Нажмите Enter для продолжения' } }
function Say($msg, $color='White') { Write-Host $msg -ForegroundColor $color }
function Fail($msg, $code=1) { Say "[ERR] $msg" Red; Pause-Script; exit $code }

Say ''
Say '=====================================================' Cyan
Say '  Комендант MDM  —  регистрация Android-устройства' Cyan
Say '=====================================================' Cyan
Say ''

if (-not (Test-Path $adb)) { Fail "adb.exe не найден рядом со скриптом ($adb)" 10 }
if (-not (Test-Path $apk)) { Fail "komendant-dpc.apk не найден рядом со скриптом ($apk)" 11 }

if ([string]::IsNullOrWhiteSpace($Link)) {
    Say 'В админ-консоли скопируйте enrollment-ссылку и вставьте сюда:'
    $Link = Read-Host 'komendant://enroll?...'
}

if (-not $Link.StartsWith('komendant://enroll?')) {
    Fail 'Ссылка должна начинаться с komendant://enroll?' 12
}

$preview = if ($Link.Length -gt 60) { $Link.Substring(0, 60) + '...' } else { $Link }
Say "  Link: $preview" DarkGray
Say ''

# [1/5] adb server
Say '[1/5] Запуск ADB сервера...'
& $adb start-server 2>&1 | Out-Null

# [2/5] проверка устройства
Say '[2/5] Проверка подключённого устройства.'
Say '  На телефоне должны быть включены:'
Say '   - Настройки > О телефоне > 7 тапов на "Номер сборки"'
Say '   - Для разработчиков > "Отладка по USB"'
Say '   - При подключении USB разрешите отладку с этого компа'
Say ''
Pause-Script
Say ''

$devices = & $adb devices | Select-Object -Skip 1 | Where-Object { $_ -match '\S' }
$connected = @()
foreach ($line in $devices) {
    $parts = ($line -split '\s+')
    if ($parts.Count -ge 2) {
        if ($parts[1] -eq 'device')       { $connected += $parts[0] }
        elseif ($parts[1] -eq 'unauthorized') {
            Fail "USB-отладка не разрешена. Нажмите 'Разрешить' на экране телефона." 20
        }
    }
}

if ($connected.Count -eq 0) { Fail 'Устройство не обнаружено. Проверьте USB-кабель и отладку.' 21 }
if ($connected.Count -gt 1) { Say "  [WARN] Подключено несколько устройств: $($connected -join ', '). Берём первое." Yellow }
$serial = $connected[0]
Say "  OK: $serial" Green
Say ''

# [3/5] install APK
Say '[3/5] Установка Комендант DPC...'
$install = & $adb -s $serial install -r -g $apk 2>&1
if ($LASTEXITCODE -ne 0) {
    Say $install Red
    Fail 'Установка APK не удалась.' 30
}
Say '  OK' Green
Say ''

# [4/5] set-device-owner / profile-owner fallback
Say '[4/5] Назначаем DPC как Device Owner...'
Say '  (устройство должно быть свежим — без Google-аккаунта и других DPC,' Gray
Say '   иначе упадём в Profile Owner / work profile.)' Gray
Say ''

$doErr = & $adb -s $serial shell dpm set-device-owner 'ru.komendant.dpc/.admin.DeviceOwnerReceiver' 2>&1
$mode = $null
if ($LASTEXITCODE -eq 0 -and $doErr -notmatch 'failed|exception|not found|java\.') {
    $mode = 'Device Owner'
} else {
    Say "  Device Owner не удался: $doErr" Yellow
    Say '  Пробуем Profile Owner...'
    $poErr = & $adb -s $serial shell dpm set-profile-owner 'ru.komendant.dpc/.admin.DeviceOwnerReceiver' 2>&1
    if ($LASTEXITCODE -eq 0 -and $poErr -notmatch 'failed|exception|not found|java\.') {
        $mode = 'Profile Owner (work profile)'
    } else {
        Say "  Profile Owner тоже не удался: $poErr" Red
        Say ''
        Say '  Решение:' Yellow
        Say '   1) Factory reset на телефоне' Yellow
        Say '   2) При setup wizard — НЕ добавлять Google-аккаунт (Skip)' Yellow
        Say '   3) Запустить enroll.ps1 ещё раз' Yellow
        Fail 'Ни DO, ни PO не назначены.' 40
    }
}
Say "  OK: $mode" Green
Say ''

# [5/6] deep-link
Say '[5/6] Открываем enrollment на устройстве...'
# Вся am-команда передаётся как один аргумент adb shell, а URL внутри — в одинарных
# кавычках, чтобы sh на устройстве не разорвал его по & (fork) и ? (globbing).
$cmd = "am start -W -a android.intent.action.VIEW -n ru.komendant.dpc/.enrollment.EnrollmentActivity -d '$Link'"
& $adb -s $serial shell $cmd | Out-Null
Say ''

# [6/6] ожидание применения политик + автоустановки корпоративных APK
Say '[6/6] Ожидание применения политики...'
Say '  Если в политике заданы корпоративные приложения (Akitorg,'
Say '  Яндекс и др.), DPC скачает и установит их автоматически.'
Say '  Это может занять 3-10 минут на 4G и меньше минуты на Wi-Fi.'
Say ''

$timeoutSec = 600
$intervalSec = 15
$elapsed = 0
$lastCount = -1
while ($elapsed -lt $timeoutSec) {
    Start-Sleep -Seconds $intervalSec
    $elapsed += $intervalSec
    # Собираем пакеты третьих сторон на устройстве (не system).
    $raw = & $adb -s $serial shell pm list packages -3 2>&1
    if ($LASTEXITCODE -ne 0) {
        Say "  [WARN] pm list packages вернул ошибку: $raw" Yellow
        break
    }
    $count = ($raw | Where-Object { $_ -match '^package:' }).Count
    if ($count -ne $lastCount) {
        Say ("  [{0:mm\:ss}] установлено сторонних пакетов: {1}" -f ([TimeSpan]::FromSeconds($elapsed)), $count) DarkGray
        $lastCount = $count
    }
    # Выходим пораньше если список стабилизировался > 3 тиков подряд.
    if ($elapsed -ge 90 -and $count -eq $lastCount) { break }
}
Say ''
Say '=====================================================' Green
Say "  ГОТОВО - mode: $mode" Green
Say '=====================================================' Green
Say ''
Say '  1. На экране телефона появится экран согласия с' Cyan
Say '     обработкой персональных данных — примите.' Cyan
Say '  2. Устройство появится в админ-консоли через' Cyan
Say '     несколько секунд. После первого policy-tick DPC' Cyan
Say '     начнёт установку корпоративных приложений в фоне.' Cyan
Say "  3. Установлено сторонних пакетов на устройстве: $lastCount" Cyan
Say ''
Pause-Script
