#!/usr/bin/env bash
# Cable setup of the family build (docs/cable-setup.md): gives Nieto, from the computer, everything adb can give,
# so "Configurar Nieto" skips those steps by itself (it reads the real state of each one):
#   - runtime permissions ("Permitir todo", notifications, missed calls, photos)            pm grant
#   - reminders on time / in full screen, "Modificar ajustes del sistema"                     appops
#   - battery without restrictions                                                            deviceidle whitelist
#   - "Leer mensajes" (message listener), "No molestar" access                                cmd notification
#   - unknown-call warning (call screening role, Android 10+)                                 cmd role
#   - the screen helper left off (Nieto)                                                      settings put secure
#   - «Pregúntale a Nieto» in the quick settings (Android 13+)                                cmd statusbar add-tile
#   - the phone's language and protected settings (CHANGE_CONFIGURATION, WRITE_SECURE_SETTINGS) pm grant
# What no computer can do stays in the wizard: the home-screen button (the launcher asks), Nieto's voice, saving
# the phone's setup, and Xiaomi/Poco "Inicio automático" (no adb switch on MIUI/HyperOS).
# Run once after installing the family build by cable, with the phone connected and USB debugging on (Xiaomi/Poco:
# also "Depuración USB (ajustes de seguridad)", else HyperOS refuses pm grant and appops).
# Usage: bash scripts/grant-family-permissions.sh <adb-serial> [<invitation link>]     (adb devices lists the serial)
# With the invitation link (npm run admin -- invite-create), Nieto opens with it at the end: after «Entrar con Google»
# she is in the family's household without typing a code (docs/onboarding.md, "One link").
set -uo pipefail
export MSYS_NO_PATHCONV=1   # Git Bash on Windows: don't rewrite component names as paths

serial="${1:-}"
invite="${2:-}"
if [ -z "$serial" ]; then
  echo "Usage: $0 <adb-serial> [<invitation link>]   (see: adb devices)" >&2
  exit 2
fi
# Only the link's shape is checked here; Nieto takes nothing from it but a code from its own site.
if [ -n "$invite" ] && ! [[ "$invite" =~ ^https://[A-Za-z0-9.-]+/i/[A-Za-z0-9-]{6,12}/?$ ]]; then
  echo "That doesn't look like an invitation link (https://<site>/i/<code>): $invite" >&2
  exit 2
fi

adb_bin="${ADB:-adb}"
if ! command -v "$adb_bin" >/dev/null 2>&1 && [ -n "${LOCALAPPDATA:-}" ]; then
  adb_bin="$(cygpath -u "$LOCALAPPDATA" 2>/dev/null || echo "$LOCALAPPDATA")/Android/Sdk/platform-tools/adb.exe"
fi
shell() { "$adb_bin" -s "$serial" shell "$@" 2>&1 | tr -d '\r'; }

# NIETO_ENV=dev: the dev app (com.jcrubio.nieto.dev, docs/delivery.md "Dev app"); its classes keep their names.
classes="com.jcrubio.nieto"
package="$classes"
[ "${NIETO_ENV:-prod}" = dev ] && package="$classes.dev"
listener="$package/$classes.messages.MessageListenerService"
helper="$package/$classes.screen.ScreenHelperService"
tile="$package/$classes.screen.ScreenTileService"

if ! shell pm list packages "$package" | grep -q "package:$package\$"; then
  echo "Nieto is not installed on $serial. Install the family build first." >&2
  exit 1
fi
dump="$(shell dumpsys package "$package")"
if ! grep -q "android.permission.WRITE_SECURE_SETTINGS" <<<"$dump"; then
  echo "This is the lite build (it doesn't declare the cable permissions). Install the family build first." >&2
  exit 1
fi
sdk="$(shell getprop ro.build.version.sdk)"
echo "Phone: $(shell getprop ro.product.manufacturer) $(shell getprop ro.product.model), Android SDK $sdk"

failed=0
# step <what> <command...>: runs it on the phone; any output with "Exception", "Error" or "not" counts as refused.
step() {
  local what="$1"
  shift
  local out
  out="$(shell "$@")"
  if grep -qiE "exception|error|not allowed|unknown|failure|denied" <<<"$out"; then
    echo "  refused  $what: $(head -n 1 <<<"$out")"
    failed=$((failed + 1))
  else
    echo "  ok       $what"
  fi
}

echo "Runtime permissions:"
runtime=(
  android.permission.RECORD_AUDIO
  android.permission.READ_CONTACTS android.permission.WRITE_CONTACTS
  android.permission.READ_CALENDAR android.permission.WRITE_CALENDAR
  android.permission.CALL_PHONE android.permission.READ_CALL_LOG
  android.permission.ACCESS_COARSE_LOCATION android.permission.ACCESS_FINE_LOCATION
)
[ "$sdk" -ge 31 ] && runtime+=(android.permission.BLUETOOTH_SCAN android.permission.BLUETOOTH_CONNECT)
if [ "$sdk" -ge 33 ]; then
  runtime+=(android.permission.POST_NOTIFICATIONS android.permission.READ_MEDIA_IMAGES)
else
  runtime+=(android.permission.READ_EXTERNAL_STORAGE)
fi
for permission in "${runtime[@]}"; do
  step "${permission#android.permission.}" pm grant "$package" "$permission"
done

echo "Computer-only permissions:"
step "CHANGE_CONFIGURATION (language)" pm grant "$package" android.permission.CHANGE_CONFIGURATION
step "WRITE_SECURE_SETTINGS (more settings)" pm grant "$package" android.permission.WRITE_SECURE_SETTINGS

echo "Special switches:"
step "Modificar ajustes del sistema" appops set "$package" WRITE_SETTINGS allow
[ "$sdk" -ge 31 ] && step "Alarmas y recordatorios" appops set "$package" SCHEDULE_EXACT_ALARM allow
[ "$sdk" -ge 34 ] && step "Pantalla completa" appops set "$package" USE_FULL_SCREEN_INTENT allow
# Android 13+: lets the family turn the listener/helper on by hand later too (sideloaded apps start restricted).
[ "$sdk" -ge 33 ] && step "Ajustes restringidos" appops set "$package" ACCESS_RESTRICTED_SETTINGS allow
step "Batería sin restricciones" cmd deviceidle whitelist "+$package"
step "Acceso a No molestar" cmd notification allow_dnd "$package"
step "Leer mensajes" cmd notification allow_listener "$listener"
[ "$sdk" -ge 29 ] && step "Avisar de llamadas desconocidas" cmd role add-role-holder android.app.role.CALL_SCREENING "$package"

# The screen helper stays OFF: with WRITE_SECURE_SETTINGS (above) Nieto turns it on only while it presses or looks,
# and off after (screen/HelperSwitch.kt). Banking apps refuse to open while it's on (Nu, 2026-10-07).
echo "Screen helper:"
enabled="$(shell settings get secure enabled_accessibility_services)"
if grep -q "$helper" <<<"$enabled"; then
  services="$(tr ':' '\n' <<<"$enabled" | grep -v "^$helper\$" | grep -v '^null$' | paste -sd: - || true)"
  if [ -n "$services" ]; then
    step "off until Nieto needs it" settings put secure enabled_accessibility_services "$services"
  else
    step "off until Nieto needs it" settings delete secure enabled_accessibility_services
  fi
else
  echo "  ok       off until Nieto needs it"
fi

if [ "$sdk" -ge 33 ]; then
  echo "Quick settings:"
  step "«Pregúntale a Nieto» tile" cmd statusbar add-tile "$tile"
fi

echo
echo "Check (what Nieto will read):"
dump="$(shell dumpsys package "$package")"
grep -E "(CHANGE_CONFIGURATION|WRITE_SECURE_SETTINGS|RECORD_AUDIO|POST_NOTIFICATIONS|READ_CALL_LOG): granted=" <<<"$dump" | sort -u | sed 's/^ */  /'
for op in WRITE_SETTINGS SCHEDULE_EXACT_ALARM USE_FULL_SCREEN_INTENT; do
  echo "  $op: $(shell appops get "$package" "$op" | head -n 1)"
done
echo "  battery whitelist: $(shell cmd deviceidle whitelist | grep -c "$package") entry"
echo "  message listener: $(shell settings get secure enabled_notification_listeners | grep -c "$listener")/1"
[ "$sdk" -ge 29 ] && echo "  call screening holder: $(shell cmd role get-role-holders android.app.role.CALL_SCREENING)"
echo "  screen helper on now: $(shell settings get secure enabled_accessibility_services | grep -c "$helper")/1 (0 expected: Nieto turns it on per use)"
if [ -n "$invite" ]; then
  echo
  echo "Invitation:"
  # Addressed to Nieto by package: it opens even before Android has checked the site (App Links).
  step "Nieto opened with the invitation" am start -a android.intent.action.VIEW -d "$invite" -p "$package"
fi
echo
if [ "$failed" -gt 0 ]; then
  echo "Done with $failed refused. Nieto asks for those in the setup (or when first needed)." >&2
  exit 1
fi
if [ -n "$invite" ]; then
  echo "Done. Nieto is open with the invitation: she presses «Entrar con Google»; the setup shows only what a computer can't do."
else
  echo "Done. Open Nieto: the setup shows only what a computer can't do."
fi
