#!/usr/bin/env bash
# Rebuild debug APK, run unit tests, reconnect known wireless adb targets, install, relaunch.
set -euo pipefail

ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$ROOT"

RECONNECT_KNOWN_DEVICES=${RECONNECT_KNOWN_DEVICES:-no}

# Hints for wireless debugging. Edit as needed.
## CONNECTIONS_LIST_HINTS[IP_WITH_UNDERLINES]="hint string"
declare -A CONNECTIONS_LIST_HINTS
## android tv projector / android 13
CONNECTIONS_LIST_HINTS["192_168_33_153"]="[A13] Android Projector"
## tab g6 max / android 16
CONNECTIONS_LIST_HINTS["192_168_33_39"]="[A16] Doogee Tab G6 Max / P8_EEA"
## bl6000pro main / android 11
CONNECTIONS_LIST_HINTS["192_168_33_106"]="[A11] BlackView BL6000Pro / BL6000Pro_EEA"
## bl6000pro aux / android 11
CONNECTIONS_LIST_HINTS["192_168_33_173"]="[A11] BlackView BL6000Pro / BL6000Pro"

get_ip_for_hint_key() {
  local ip=${1}
  ip="$(echo "${ip}" | sed -e s'@_@\.@g' -e s'@:.*@@' | tr -d '\n' )"
  printf "%s" "${ip}"
}

get_hint_key_for_ip() {
  local ip=${1}
  ip="$(echo "${ip}" | sed -e s'@\.@_@g' -e s'@:.*@@' | tr -d '\n' )"
  printf "%s" "${ip}"
}

get_hint() {
  local ip_mask="${1}"
  local -n hint
  ip_mask="$(get_hint_key_for_ip "${ip_mask}")"
  hint=CONNECTIONS_LIST_HINTS[${ip_mask}]
  printf "%s" "${hint}"
}

APK="$ROOT/app/build/outputs/apk/debug/app-debug.apk"
PACKAGE="com.foxx.androidcast"
LAUNCHER="$PACKAGE/.MainActivity"

RUN_UNIT_TESTS="${RUN_UNIT_TESTS:-1}"
ADB_CONNECT_RETRIES="${ADB_CONNECT_RETRIES:-4}"
ADB_CONNECT_DELAY_SEC="${ADB_CONNECT_DELAY_SEC:-2}"

for arg in "$@"; do
  case "$arg" in
    --skip-tests) RUN_UNIT_TESTS=0 ;;
    --no-tests) RUN_UNIT_TESTS=0 ;;
    --java-home=*)
      ANDROID_CAST_JAVA_HOME="${arg#--java-home=}"
      ;;
    -h|--help)
      echo "Usage: $0 [--skip-tests] [--java-home=PATH]"
      echo "  Builds debug APK, runs unit tests (unless skipped), reconnects devices in CONNECTIONS_LIST_HINTS,"
      echo "  installs on all adb devices in 'device' state, and launches the app."
      exit 0
      ;;
  esac
done

pick_java_home() {
  if [[ -n "${ANDROID_CAST_JAVA_HOME:-}" && -x "${ANDROID_CAST_JAVA_HOME}/bin/java" ]]; then
    echo "$ANDROID_CAST_JAVA_HOME"
    return 0
  fi
  local c
  for c in /usr/lib/jvm/openjdk-bin-21 /usr/lib/jvm/java-21-openjdk; do
    if [[ -x "$c/bin/java" ]]; then
      echo "$c"
      return 0
    fi
  done
  for c in /usr/lib/jvm/openjdk-bin-17 /usr/lib/jvm/java-17-openjdk; do
    if [[ -x "$c/bin/java" ]]; then
      echo "$c"
      return 0
    fi
  done
  return 1
}

if [[ -n "${JAVA_HOME:-}" && -x "${JAVA_HOME}/bin/java" ]]; then
  jver="$("${JAVA_HOME}/bin/java" -version 2>&1 | head -1)"
  if [[ "$jver" =~ version\ \"(2[5-9]|[3-9][0-9]) ]]; then
    echo "WARN: JAVA_HOME is too new for Gradle 8.9 ($JAVA_HOME — $jver)."
    echo "      Picking a supported JDK (17–21). Set ANDROID_CAST_JAVA_HOME to override."
  fi
fi

if ! picked="$(pick_java_home)"; then
  echo "ERROR: No JDK 17 or 21 found. Install openjdk-bin-21 or set ANDROID_CAST_JAVA_HOME." >&2
  exit 1
fi
export JAVA_HOME="$picked"

reconnect_endpoint() {
  local endpoint="$1"
  [[ -z "$endpoint" ]] && return 1
  local attempt out
  local hint=""
  hint="$(get_hint "${endpoint}")"
  [[ -n "${hint}" ]] && hint="(having hint: ${hint})"
  echo "   trying to connect to $endpoint ${hint}"
  adb disconnect "$endpoint" >/dev/null 2>&1 || true
  for (( attempt = 1; attempt <= ADB_CONNECT_RETRIES; attempt++ )); do
    out="$(adb connect "$endpoint" 2>&1)" || true
    if grep -qiE 'connected|already' <<<"$out"; then
      if adb -s "$endpoint" get-state 2>/dev/null | grep -q '^device$'; then
        echo "    $endpoint — ready"
        return 0
      fi
    fi
    if [[ "$attempt" -lt "$ADB_CONNECT_RETRIES" ]]; then
      sleep "$ADB_CONNECT_DELAY_SEC"
    fi
  done
  echo "    $endpoint — not reachable ($out)" >&2
  return 1
}

reconnect_known_devices() {
  echo "==> Reconnecting known wireless adb endpoints"
  adb start-server >/dev/null 2>&1 || true
  adb reconnect offline >/dev/null 2>&1 || true
  local endpoint
  for endpoint in "${!CONNECTIONS_LIST_HINTS[@]}"; do
    reconnect_endpoint "$(get_ip_for_hint_key "$endpoint")" || true
  done
  adb devices -l
}

# shellcheck source=scripts/android-ndk.sh
source "$ROOT/scripts/android-ndk.sh"
# shellcheck source=scripts/native-build-cache.sh
source "$ROOT/scripts/native-build-cache.sh"
export ANDROIDCAST_ROOT="$ROOT"
export ANDROID_NDK_HOME="$(androidcast_find_ndk_root "$ROOT")"
export ANDROID_NDK_ROOT="$ANDROID_NDK_HOME"
echo "==> Using NDK: $ANDROID_NDK_HOME"
if androidcast_ccache_wanted 2>/dev/null; then
  echo "==> Native ccache: enabled (ANDROIDCAST_CCACHE=${ANDROIDCAST_CCACHE:-auto})"
else
  echo "==> Native ccache: disabled"
fi

# Match app/build.gradle defaultConfig.ndk.abiFilters
ARCH_ABIS="armeabi-v7a arm64-v8a x86_64"
echo "==> Building libvpx for: ${ARCH_ABIS}"
rm -rf "$ROOT/build/native"
mkdir -p "$ROOT/build/native"
for ARCH_ABI in ${ARCH_ABIS}; do
  unset ANDROIDCAST_LIBVPX_LIB
  LC_ALL=C ./scripts/build-native-codecs.sh "${ARCH_ABI}"
done

echo "==> Building debug APK (JAVA_HOME=$JAVA_HOME)"
# Docker CI on a mounted repo leaves app/.cxx with /opt/android-sdk paths; that breaks local clean/build.
rm -rf "$ROOT/app/.cxx"
if [[ -d "$ROOT/app/build" ]] && ! rm -rf "$ROOT/app/build" 2>/dev/null; then
  echo "WARN: app/build is not writable (often root-owned after Docker). Run: sudo rm -rf app/build" >&2
fi
./gradlew --stop
./gradlew clean
./gradlew --build-cache assembleDebug

if [[ "$RUN_UNIT_TESTS" == "1" ]]; then
  echo "==> Running unit tests (./gradlew testDebugUnitTest)"
  ./gradlew testDebugUnitTest
else
  echo "==> Skipping unit tests (RUN_UNIT_TESTS=$RUN_UNIT_TESTS)"
fi

if [[ ! -f "$APK" ]]; then
  echo "ERROR: APK not found at $APK" >&2
  exit 1
fi

if [[ "${RECONNECT_KNOWN_DEVICES}" =~ "[yY]*" ]]; then
  reconnect_known_devices
fi

mapfile -t DEVICES < <(adb devices | awk 'NR > 1 && $2 == "device" { print $1 }')

if [[ ${#DEVICES[@]} -eq 0 ]]; then
  echo "ERROR: No adb devices in 'device' state after reconnect." >&2
  echo "       Wake devices, re-enable wireless debugging, or: adb connect HOST:5555" >&2
  exit 1
fi

echo "==> Installing to ${#DEVICES[@]} device(s): ${DEVICES[*]}"
FAILED=0
for serial in "${DEVICES[@]}"; do
  echo "--- $serial"
  if adb -s "$serial" install -r "$APK"; then
    echo "    Installed"
    if adb -s "$serial" shell am start -n "$LAUNCHER" -a android.intent.action.MAIN -c android.intent.category.LAUNCHER; then
      echo "    Launched $LAUNCHER"
    else
      echo "    WARN: launch failed (app may still be installed)" >&2
    fi
  else
    echo "    FAILED" >&2
    FAILED=$((FAILED + 1))
  fi
done

if [[ $FAILED -gt 0 ]]; then
  echo "Done with $FAILED failure(s)." >&2
  exit 1
fi

echo "Done. APK: $APK"
echo "Open this folder in Android Studio: $ROOT"
