#!/usr/bin/env bash
set -u

APP="${APP:-com.cpt.electronicmenu.tv}"
HOME_PKG="${HOME_PKG:-com.mitv.tvhome}"
HOME_ACTIVITY="${HOME_ACTIVITY:-com.mitv.tvhome/.MainActivityUserMode}"
PORT="${PORT:-5555}"
CONCURRENCY="${CONCURRENCY:-4}"
CONNECT_TIMEOUT="${CONNECT_TIMEOUT:-8}"
STEP_TIMEOUT="${STEP_TIMEOUT:-30}"
RETRY="${RETRY:-2}"

usage() {
  printf 'Usage: %s [--yes] <tv_ips.txt>\n' "$0"
  printf 'Dry-run is default. Add --yes to write settings.\n'
}

YES=0
if [ "${1:-}" = "--yes" ]; then
  YES=1
  shift
fi

IP_FILE="${1:-}"
if [ -z "$IP_FILE" ]; then
  usage
  exit 2
fi

if [ ! -f "$IP_FILE" ]; then
  printf 'IP file not found: %s\n' "$IP_FILE" >&2
  exit 2
fi

if ! command -v adb >/dev/null 2>&1; then
  printf 'adb command not found. Install Android platform-tools first.\n' >&2
  exit 127
fi

RUN_ID="$(date '+%Y%m%d-%H%M%S')"
LOG_DIR="${LOG_DIR:-logs/tv-config-$RUN_ID}"
mkdir -p "$LOG_DIR"
RESULT_DIR="$(mktemp -d "${TMPDIR:-/tmp}/redmi-tv-autostart.XXXXXX")"
trap 'rm -rf "$RESULT_DIR"' EXIT

is_ipv4() {
  case "$1" in
    *[!0-9.]* | "" | *..* | .* | *.) return 1 ;;
  esac
  awk -F. 'NF == 4 {
    for (i = 1; i <= 4; i++) {
      if ($i == "" || $i < 0 || $i > 255) exit 1
    }
    exit 0
  } { exit 1 }' <<EOF_IP
$1
EOF_IP
}

run_with_timeout() {
  seconds="$1"
  shift
  "$@" &
  pid=$!
  elapsed=0
  while kill -0 "$pid" 2>/dev/null; do
    if [ "$elapsed" -ge "$seconds" ]; then
      kill "$pid" 2>/dev/null || true
      wait "$pid" 2>/dev/null || true
      return 124
    fi
    sleep 1
    elapsed=$((elapsed + 1))
  done
  wait "$pid"
}

run_adb() {
  serial="$1"
  shift
  run_with_timeout "$STEP_TIMEOUT" adb -s "$serial" "$@"
}

log_line() {
  log_file="$1"
  shift
  printf '[%s] %s\n' "$(date '+%F %T')" "$*" >>"$log_file"
}

write_result() {
  ip="$1"
  status="$2"
  step="$3"
  detail="$4"
  attempts="$5"
  started="$6"
  ended="$(date '+%F %T')"
  printf '%s,%s,%s,%s,%s,%s,%s\n' "$ip" "$started" "$ended" "$status" "$step" "$attempts" "$detail" >"$RESULT_DIR/$ip.csv"
}

configure_one() {
  ip="$1"
  serial="$ip:$PORT"
  log_file="$LOG_DIR/$ip.log"
  started="$(date '+%F %T')"
  attempts=0

  : >"$log_file"
  log_line "$log_file" "serial=$serial app=$APP dry_run=$((1 - YES))"

  if ! is_ipv4 "$ip"; then
    log_line "$log_file" "invalid IPv4 address"
    write_result "$ip" "FAIL" "validate_ip" "invalid_ip" "$attempts" "$started"
    return 1
  fi

  while [ "$attempts" -le "$RETRY" ]; do
    attempts=$((attempts + 1))
    log_line "$log_file" "connect attempt $attempts"
    connect_output="$(run_with_timeout "$CONNECT_TIMEOUT" adb connect "$serial" 2>&1)"
    connect_code=$?
    log_line "$log_file" "adb connect exit=$connect_code output=$connect_output"

    state_output="$(run_with_timeout "$CONNECT_TIMEOUT" adb -s "$serial" get-state 2>&1)"
    state_code=$?
    log_line "$log_file" "get-state exit=$state_code output=$state_output"

    if [ "$state_code" -eq 0 ] && [ "$state_output" = "device" ]; then
      break
    fi

    if printf '%s\n%s\n' "$connect_output" "$state_output" | grep -qi 'unauthorized'; then
      write_result "$ip" "FAIL" "authorize" "unauthorized_allow_on_tv" "$attempts" "$started"
      return 1
    fi

    if [ "$attempts" -gt "$RETRY" ]; then
      write_result "$ip" "FAIL" "connect" "$(printf '%s' "$state_output" | tr ',' ' ')" "$attempts" "$started"
      return 1
    fi

    sleep 5
  done

  app_path="$(run_adb "$serial" shell pm path "$APP" 2>&1)"
  app_code=$?
  log_line "$log_file" "pm path app exit=$app_code output=$app_path"
  if [ "$app_code" -ne 0 ] || ! printf '%s\n' "$app_path" | grep -q '^package:'; then
    write_result "$ip" "FAIL" "check_app" "app_not_installed" "$attempts" "$started"
    return 1
  fi

  before_value="$(run_adb "$serial" shell settings get system start_3rd_app 2>&1 | tr -d '\r')"
  log_line "$log_file" "before start_3rd_app=$before_value"

  disabled_home="$(run_adb "$serial" shell pm list packages -d 2>&1 | grep "^package:$HOME_PKG$" || true)"
  log_line "$log_file" "disabled_home=$disabled_home"

  if [ "$YES" -ne 1 ]; then
    write_result "$ip" "DRY_RUN" "dry_run" "would_configure" "$attempts" "$started"
    return 0
  fi

  home_path="$(run_adb "$serial" shell pm path "$HOME_PKG" 2>&1)"
  home_code=$?
  log_line "$log_file" "pm path home exit=$home_code output=$home_path"
  if [ "$home_code" -eq 0 ] && printf '%s\n' "$home_path" | grep -q '^package:'; then
    enable_output="$(run_adb "$serial" shell pm enable "$HOME_PKG" 2>&1)"
    enable_code=$?
    log_line "$log_file" "pm enable home exit=$enable_code output=$enable_output"
  else
    log_line "$log_file" "home package not found, skip pm enable"
  fi

  put_output="$(run_adb "$serial" shell settings put system start_3rd_app "$APP" 2>&1)"
  put_code=$?
  log_line "$log_file" "settings put exit=$put_code output=$put_output"
  if [ "$put_code" -ne 0 ]; then
    write_result "$ip" "FAIL" "settings_put" "$(printf '%s' "$put_output" | tr ',' ' ')" "$attempts" "$started"
    return 1
  fi

  after_value="$(run_adb "$serial" shell settings get system start_3rd_app 2>&1 | tr -d '\r')"
  log_line "$log_file" "after start_3rd_app=$after_value"
  if [ "$after_value" != "$APP" ]; then
    write_result "$ip" "FAIL" "settings_get" "actual=$after_value" "$attempts" "$started"
    return 1
  fi

  start_output="$(run_adb "$serial" shell am start -n "$HOME_ACTIVITY" 2>&1)"
  start_code=$?
  log_line "$log_file" "am start home exit=$start_code output=$start_output"
  if [ "$start_code" -ne 0 ]; then
    key_output="$(run_adb "$serial" shell input keyevent HOME 2>&1)"
    key_code=$?
    log_line "$log_file" "fallback HOME exit=$key_code output=$key_output"
  fi

  write_result "$ip" "OK" "done" "configured" "$attempts" "$started"
}

ips_file="$RESULT_DIR/ips.txt"
while IFS= read -r line || [ -n "$line" ]; do
  ip="$(printf '%s' "$line" | sed 's/[[:space:]]//g')"
  [ -z "$ip" ] && continue
  case "$ip" in \#*) continue ;; esac
  printf '%s\n' "$ip" >>"$ips_file"
done <"$IP_FILE"

if [ ! -s "$ips_file" ]; then
  printf 'No IPs found in %s\n' "$IP_FILE" >&2
  exit 2
fi

printf 'log_dir=%s\n' "$LOG_DIR"
if [ "$YES" -ne 1 ]; then
  printf 'mode=dry-run; add --yes to write settings\n'
fi

active=0
while IFS= read -r ip; do
  configure_one "$ip" &
  active=$((active + 1))
  if [ "$active" -ge "$CONCURRENCY" ]; then
    wait -n 2>/dev/null || wait
    active=$((active - 1))
  fi
done <"$ips_file"
wait

summary="$LOG_DIR/summary.csv"
printf 'ip,start_time,end_time,status,step,attempts,detail\n' >"$summary"
while IFS= read -r ip; do
  if [ -f "$RESULT_DIR/$ip.csv" ]; then
    cat "$RESULT_DIR/$ip.csv" >>"$summary"
  else
    printf '%s,,,,FAIL,no_result\n' "$ip" >>"$summary"
  fi
done <"$ips_file"

printf '\nSummary:\n'
cat "$summary"

if grep -q ',FAIL,' "$summary"; then
  exit 1
fi
