#!/bin/sh
set -eu

ANYY_RELEASE_BASE_URL="${ANYY_RELEASE_BASE_URL:-https://anyy.ai/releases}"
ANYY_RELEASE_BASE_URL="${ANYY_RELEASE_BASE_URL%/}"
ANYY_LATEST_URL="${ANYY_LATEST_URL:-$ANYY_RELEASE_BASE_URL/latest}"
ANYY_INSTALL_COMPACT="${ANYY_INSTALL_COMPACT:-0}"
ANYY_RELEASE_ACTIVATED=0
ANYY_NO_ACTIVATION_REPORTED=0
ANYY_USAGE_EXIT=0
PREVIOUS_RELEASE_TMP=
INSTALL_TEMP_MARKER=".anyy-install-temp"
INSTALL_SPACE_RESERVE_BYTES=1048576
LINK_USR_BIN="${LINK_USR_BIN:-auto}"

die() {
  echo "install.sh: $*" >&2
  exit 1
}

report_no_activation_on_failure() {
  anyy_exit_status="$1"
  if [ "$anyy_exit_status" != "0" ] &&
    [ "${ANYY_USAGE_EXIT:-0}" != "1" ] &&
    [ "${ANYY_RELEASE_ACTIVATED:-0}" != "1" ] &&
    [ "${ANYY_NO_ACTIVATION_REPORTED:-0}" != "1" ]; then
    echo "No release was activated." >&2
    ANYY_NO_ACTIVATION_REPORTED=1
  fi
}

trap 'anyy_status=$?; report_no_activation_on_failure "$anyy_status"; exit "$anyy_status"' EXIT

log_step() {
  printf '%s\n' "$*"
}

resolve_home() {
  if [ "${ANYY_HOME:-}" ]; then
    printf '%s\n' "$ANYY_HOME"
    return
  fi
  if [ "$(id -u)" = "0" ]; then
    printf '%s\n' "/root/.anyy"
    return
  fi
  if [ -z "${HOME:-}" ]; then
    die "HOME is not set; set ANYY_HOME"
  fi
  printf '%s\n' "$HOME/.anyy"
}

detect_os_arch() {
  os_name="$(uname -s)"
  arch_name="$(uname -m)"
  case "$os_name" in
    Darwin) os="darwin" ;;
    Linux) os="linux" ;;
    *) die "unsupported operating system: $os_name" ;;
  esac
  case "$arch_name" in
    x86_64 | amd64) arch="amd64" ;;
    arm64 | aarch64) arch="arm64" ;;
    *) die "unsupported architecture: $arch_name" ;;
  esac
  printf '%s %s\n' "$os" "$arch"
}

validate_version() {
  version="$1"
  case "$version" in
    "" | latest | *[\\/]*)
      die "invalid VERSION: $version"
      ;;
    dev)
      return 0
      ;;
    v*.*.*)
      ;;
    *)
      die "invalid VERSION: $version"
      ;;
  esac

  version_parts="${version#v}"
  major="${version_parts%%.*}"
  version_parts="${version_parts#*.}"
  minor="${version_parts%%.*}"
  patch="${version_parts#*.}"
  case "$patch" in
    *.*)
      die "invalid VERSION: $version"
      ;;
  esac
  for part in "$major" "$minor" "$patch"; do
    case "$part" in
      "" | *[!0-9]*)
        die "invalid VERSION: $version"
        ;;
    esac
  done
}

is_release_version() {
  anyy_release_candidate="$1"
  case "$anyy_release_candidate" in
    "" | latest | *[\\/]*)
      return 1
      ;;
    dev)
      return 0
      ;;
    v*.*.*)
      ;;
    *)
      return 1
      ;;
  esac

  anyy_release_parts="${anyy_release_candidate#v}"
  anyy_release_major="${anyy_release_parts%%.*}"
  anyy_release_parts="${anyy_release_parts#*.}"
  anyy_release_minor="${anyy_release_parts%%.*}"
  anyy_release_patch="${anyy_release_parts#*.}"
  case "$anyy_release_patch" in
    *.*)
      return 1
      ;;
  esac
  for anyy_release_part in "$anyy_release_major" "$anyy_release_minor" "$anyy_release_patch"; do
    case "$anyy_release_part" in
      "" | *[!0-9]*)
        return 1
        ;;
    esac
  done
  return 0
}

resolve_latest_version() {
  if [ "${VERSION:-}" ]; then
    validate_version "$VERSION"
    printf '%s\n' "$VERSION"
    return
  fi
  command -v curl >/dev/null 2>&1 || die "curl is required for release install"
  version="$(curl -fsSL "$ANYY_LATEST_URL" | sed -n '1p' | tr -d ' \t\r\n')"
  if [ -z "$version" ]; then
    die "could not resolve latest Anyy release"
  fi
  validate_version "$version"
  printf '%s\n' "$version"
}

require_command() {
  command_name="$1"
  command -v "$command_name" >/dev/null 2>&1 || die "$command_name is required for release install"
}

require_gzip() {
  if command -v gzip >/dev/null 2>&1; then
    return 0
  fi
  for gzip_path in /bin/gzip /usr/bin/gzip /usr/local/bin/gzip /opt/homebrew/bin/gzip; do
    if [ -x "$gzip_path" ]; then
      return 0
    fi
  done
  die "gzip is required for release install"
}

require_checksum_command() {
  if command -v sha256sum >/dev/null 2>&1; then
    return 0
  fi
  if command -v shasum >/dev/null 2>&1; then
    return 0
  fi
  die "sha256sum or shasum is required"
}

bytes_available() {
  path="$1"
  if ! command -v df >/dev/null 2>&1; then
    echo 1099511627776
    return 0
  fi
  anyy_df_output="$(df -Pk "$path" 2>/dev/null)" || return 1
  anyy_df_blocks="$(printf '%s\n' "$anyy_df_output" | awk 'NR == 2 { print $4 }')" || return 1
  case "$anyy_df_blocks" in
    "" | *[!0-9]*)
      return 1
      ;;
  esac
  awk -v blocks="$anyy_df_blocks" 'BEGIN { printf "%.0f\n", blocks * 1024 }' || return 1
}

create_private_temp_file() {
  anyy_tmp_dir="$1"
  anyy_tmp_prefix="$2"
  anyy_tmp_try=0
  while [ "$anyy_tmp_try" -lt 10 ]; do
    if [ "$anyy_tmp_try" = "0" ]; then
      anyy_tmp_path="$anyy_tmp_dir/$anyy_tmp_prefix.$$"
    else
      anyy_tmp_path="$anyy_tmp_dir/$anyy_tmp_prefix.$$.$anyy_tmp_try"
    fi
    if [ -e "$anyy_tmp_path" ] || [ -L "$anyy_tmp_path" ]; then
      anyy_tmp_try=$((anyy_tmp_try + 1))
      continue
    fi
    if (set -C; : >"$anyy_tmp_path") 2>/dev/null; then
      if chmod 600 "$anyy_tmp_path"; then
        printf '%s\n' "$anyy_tmp_path"
        return 0
      fi
      rm -f "$anyy_tmp_path"
      return 1
    fi
    anyy_tmp_try=$((anyy_tmp_try + 1))
  done
  return 1
}

path_size_bytes() {
  path="$1"
  if [ ! -e "$path" ]; then
    echo 0
    return
  fi
  if ! command -v du >/dev/null 2>&1; then
    echo 0
    return
  fi
  du -sk "$path" | awk '{ printf "%.0f\n", $1 * 1024 }'
}

format_mb() {
  bytes="$1"
  awk -v b="$bytes" 'BEGIN { printf "%.1f MB", b / 1024 / 1024 }'
}

is_stale_temp_entry() {
  path="$1"
  entry_type="$2"
  command -v find >/dev/null 2>&1 || return 1
  current_uid="$(id -u 2>/dev/null || printf '%s\n' "")"
  [ -n "$current_uid" ] || return 1
  stale_path="$(find "$path" -prune -type "$entry_type" -user "$current_uid" -mtime +1 -print 2>/dev/null | sed -n '1p')"
  [ "$stale_path" = "$path" ]
}

cleanup_install_temps() {
  tmp_root="${TMPDIR:-/tmp}"
  anyy_install_temp_marker="${INSTALL_TEMP_MARKER:-.anyy-install-temp}"
  freed=0
  for path in "$tmp_root"/anyy-install.??????; do
    [ -e "$path" ] || continue
    [ -L "$path" ] && continue
    [ -d "$path" ] || continue
    is_stale_temp_entry "$path" d || continue
    [ -L "$path" ] && continue
    [ -d "$path" ] || continue
    [ -L "$path/$anyy_install_temp_marker" ] && continue
    [ -f "$path/$anyy_install_temp_marker" ] || continue
    size="$(path_size_bytes "$path")"
    if rm -rf "$path"; then
      freed=$((freed + size))
    else
      echo "install.sh: warning: could not remove stale temp directory: $path" >&2
    fi
  done
  for path in "$tmp_root"/anyy-update-*.bin "$tmp_root"/anyy-update-*.tar.gz; do
    [ -e "$path" ] || continue
    [ -L "$path" ] && continue
    [ -f "$path" ] || continue
    is_stale_temp_entry "$path" f || continue
    [ -L "$path" ] && continue
    [ -f "$path" ] || continue
    size="$(path_size_bytes "$path")"
    if rm -f "$path"; then
      freed=$((freed + size))
    else
      echo "install.sh: warning: could not remove stale temp file: $path" >&2
    fi
  done
  CLEANUP_FREED_BYTES="$freed"
}

current_release_version() {
  home="$1"
  anyy_current_home="$home"
  while [ "$anyy_current_home" != "/" ] && [ "${anyy_current_home%/}" != "$anyy_current_home" ]; do
    anyy_current_home="${anyy_current_home%/}"
  done
  if [ -L "$home/current" ]; then
    anyy_current_target="$(readlink "$home/current" 2>/dev/null || true)"
    case "$anyy_current_target" in
      releases/*)
        anyy_current_version="${anyy_current_target#releases/}"
        if is_release_version "$anyy_current_version"; then
          printf '%s\n' "$anyy_current_version"
          return
        fi
        ;;
      "$anyy_current_home"/releases/*)
        anyy_current_version="${anyy_current_target#"$anyy_current_home"/releases/}"
        if is_release_version "$anyy_current_version"; then
          printf '%s\n' "$anyy_current_version"
          return
        fi
        ;;
    esac
  fi
  printf '%s\n' ""
}

previous_release_version() {
  home="$1"
  anyy_previous_path="$home/.install/previous"
  if [ -L "$anyy_previous_path" ]; then
    die ".install/previous path is a symlink: $anyy_previous_path"
  fi
  if [ -e "$anyy_previous_path" ] && [ ! -f "$anyy_previous_path" ]; then
    die ".install/previous path is not a regular file: $anyy_previous_path"
  fi
  if [ ! -f "$anyy_previous_path" ]; then
    printf '%s\n' ""
    return
  fi
  anyy_previous_version="$(sed -n '1p' "$anyy_previous_path" | tr -d ' \t\r\n')"
  if [ -z "$anyy_previous_version" ]; then
    printf '%s\n' ""
    return
  fi
  if is_release_version "$anyy_previous_version"; then
    printf '%s\n' "$anyy_previous_version"
    return
  fi
  die "invalid previous release marker: $anyy_previous_version"
}

stage_previous_release() {
  home="$1"
  anyy_previous_value="$2"
  PREVIOUS_RELEASE_TMP=
  [ -n "$anyy_previous_value" ] || return 0
  validate_version "$anyy_previous_value"
  mkdir -p "$home/.install"
  ensure_previous_release_path_safe "$home"
  anyy_previous_tmp="$(create_private_temp_file "$home/.install" ".previous.tmp")" || die "could not stage previous release marker"
  if ! printf '%s\n' "$anyy_previous_value" >"$anyy_previous_tmp"; then
    rm -f "$anyy_previous_tmp"
    die "could not stage previous release marker"
  fi
  if ! chmod 600 "$anyy_previous_tmp"; then
    rm -f "$anyy_previous_tmp"
    die "could not stage previous release marker"
  fi
  PREVIOUS_RELEASE_TMP="$anyy_previous_tmp"
}

commit_previous_release() {
  home="$1"
  [ -n "${PREVIOUS_RELEASE_TMP:-}" ] || return 0
  ensure_previous_release_path_safe "$home"
  if ! mv "$PREVIOUS_RELEASE_TMP" "$home/.install/previous"; then
    echo "install.sh: could not update previous release marker" >&2
    anyy_previous_tmp="$PREVIOUS_RELEASE_TMP"
    PREVIOUS_RELEASE_TMP=
    rm -f "$anyy_previous_tmp" || true
    clear_previous_release_marker "$home"
    return 1
  fi
  if ! chmod 600 "$home/.install/previous"; then
    echo "install.sh: could not set previous release marker permissions" >&2
  fi
  PREVIOUS_RELEASE_TMP=
  return 0
}

ensure_previous_release_path_safe() {
  anyy_previous_path="$1/.install/previous"
  if [ -L "$anyy_previous_path" ]; then
    die ".install/previous path is a symlink: $anyy_previous_path"
  fi
  if [ -e "$anyy_previous_path" ] && [ ! -f "$anyy_previous_path" ]; then
    die ".install/previous path is not a regular file: $anyy_previous_path"
  fi
}

clear_previous_release_marker() {
  home="$1"
  ensure_previous_release_path_safe "$home"
  rm -f "$home/.install/previous" || die "could not clear previous release marker"
}

prune_inactive_releases() {
  home="$1"
  anyy_prune_compact="$2"
  anyy_prune_current="$(current_release_version "$home")"
  anyy_prune_previous="$(previous_release_version "$home")"
  [ -L "$home/releases" ] && return 0
  [ -d "$home/releases" ] || return 0
  for anyy_prune_dir in "$home"/releases/*; do
    [ -L "$anyy_prune_dir" ] && continue
    [ -d "$anyy_prune_dir" ] || continue
    anyy_prune_version="${anyy_prune_dir##*/}"
    is_release_version "$anyy_prune_version" || continue
    [ "$anyy_prune_version" = "$anyy_prune_current" ] && continue
    if [ "$anyy_prune_version" = "$anyy_prune_previous" ] && [ "$anyy_prune_compact" != "1" ]; then
      continue
    fi
    rm -rf "$anyy_prune_dir"
  done
}

run_install_preflight() {
	home="$1"
	archive_need="$2"
	binary_need="$3"
	compact="$4"
  ensure_home_path_safe "$home"
  log_step "Preflight:"
	cleanup_install_temps
	tmp_free="$(bytes_available "${TMPDIR:-/tmp}")" || die "Preflight failed: could not check temp space"
  case "$tmp_free" in
    "" | *[!0-9]*)
      die "Preflight failed: could not check temp space"
      ;;
	esac
	mkdir -p "$home"
	space_reserve="${INSTALL_SPACE_RESERVE_BYTES:-1048576}"
  tmp_need=$((archive_need + binary_need * 2 + space_reserve))
  home_need=$((binary_need + space_reserve))
  log_step "  tmp: $(format_mb "$tmp_free") free, need $(format_mb "$tmp_need")"
  if [ "$tmp_free" -lt "$tmp_need" ]; then
    die "Preflight failed: not enough temp space"
  fi
  if [ "$compact" = "1" ]; then
    prune_inactive_releases "$home" 0
  fi
  home_free="$(bytes_available "$home")" || die "Preflight failed: could not check home space"
  case "$home_free" in
    "" | *[!0-9]*)
      die "Preflight failed: could not check home space"
      ;;
  esac
  log_step "  home: $(format_mb "$home_free") free, need $(format_mb "$home_need")"
  log_step "  rollback history: preserving current and previous releases"
  if [ "$home_free" -lt "$home_need" ] && [ "$compact" = "1" ]; then
    compact_previous="$(previous_release_version "$home")"
    compact_previous_can_prune=0
    if [ -n "$compact_previous" ] &&
      [ ! -L "$home/releases/$compact_previous" ] &&
      [ -d "$home/releases/$compact_previous" ]; then
      compact_previous_size="$(path_size_bytes "$home/releases/$compact_previous")"
      if [ $((home_free + compact_previous_size)) -ge "$home_need" ]; then
        compact_previous_can_prune=1
      fi
    fi
    if [ "$compact_previous_can_prune" = "1" ]; then
      clear_previous_release_marker "$home"
      prune_inactive_releases "$home" 1
      if [ -n "$compact_previous" ] && [ ! -d "$home/releases/$compact_previous" ]; then
        log_step "  rollback history limited: previous rollback history pruned"
      fi
      home_free="$(bytes_available "$home")" || die "Preflight failed: could not check home space after compact cleanup"
      case "$home_free" in
        "" | *[!0-9]*)
          die "Preflight failed: could not check home space after compact cleanup"
          ;;
      esac
      log_step "  home after compact cleanup: $(format_mb "$home_free") free, need $(format_mb "$home_need")"
    fi
  fi
	if [ "$home_free" -lt "$home_need" ]; then
		die "Preflight failed: not enough home space"
	fi
}

run_release_download_preflight() {
	home="$1"
	archive_need="$2"
	compact="$3"
	ensure_home_path_safe "$home"
	RELEASE_WORK_PARENT=
	log_step "Preflight:"
	cleanup_install_temps
	mkdir -p "$home"
	mkdir -p "$home/.install"
	if [ "$compact" = "1" ]; then
		prune_inactive_releases "$home" 0
	fi
	tmp_root="${TMPDIR:-/tmp}"
	tmp_free="$(bytes_available "$tmp_root")" || die "Preflight failed: could not check temp space"
	case "$tmp_free" in
		"" | *[!0-9]*)
			die "Preflight failed: could not check temp space"
			;;
	esac
	space_reserve="${INSTALL_SPACE_RESERVE_BYTES:-1048576}"
	tmp_need=$((archive_need + space_reserve))
	if [ "$tmp_free" -ge "$tmp_need" ]; then
		RELEASE_WORK_PARENT="$tmp_root"
		log_step "  tmp: $(format_mb "$tmp_free") free, need $(format_mb "$tmp_need") to download release"
		return
	fi
	log_step "  tmp: insufficient, $(format_mb "$tmp_free") free, need $(format_mb "$tmp_need") to download release"
	home_free="$(bytes_available "$home")" || die "Preflight failed: could not check home space"
	case "$home_free" in
		"" | *[!0-9]*)
			die "Preflight failed: could not check home space"
			;;
	esac
	home_need=$((archive_need + space_reserve))
	log_step "  home: $(format_mb "$home_free") free, need $(format_mb "$home_need") to download release"
	if [ "$home_free" -lt "$home_need" ]; then
		die "Preflight failed: not enough temp or home space"
	fi
	RELEASE_WORK_PARENT="$home/.install"
}

run_release_install_preflight() {
	home="$1"
	binary_need="$2"
	compact="$3"
	home_free="$(bytes_available "$home")" || die "Preflight failed: could not check home space"
	case "$home_free" in
		"" | *[!0-9]*)
			die "Preflight failed: could not check home space"
			;;
	esac
	space_reserve="${INSTALL_SPACE_RESERVE_BYTES:-1048576}"
	home_need=$((binary_need + space_reserve))
	log_step "  home: $(format_mb "$home_free") free, need $(format_mb "$home_need") to activate release"
	log_step "  rollback history: preserving current and previous releases"
	if [ "$home_free" -lt "$home_need" ] && [ "$compact" = "1" ]; then
		compact_previous="$(previous_release_version "$home")"
		compact_previous_can_prune=0
		if [ -n "$compact_previous" ] &&
			[ ! -L "$home/releases/$compact_previous" ] &&
			[ -d "$home/releases/$compact_previous" ]; then
			compact_previous_size="$(path_size_bytes "$home/releases/$compact_previous")"
			if [ $((home_free + compact_previous_size)) -ge "$home_need" ]; then
				compact_previous_can_prune=1
			fi
		fi
		if [ "$compact_previous_can_prune" = "1" ]; then
			clear_previous_release_marker "$home"
			prune_inactive_releases "$home" 1
			if [ -n "$compact_previous" ] && [ ! -d "$home/releases/$compact_previous" ]; then
				log_step "  rollback history limited: previous rollback history pruned"
			fi
			home_free="$(bytes_available "$home")" || die "Preflight failed: could not check home space after compact cleanup"
			case "$home_free" in
				"" | *[!0-9]*)
					die "Preflight failed: could not check home space after compact cleanup"
					;;
			esac
			log_step "  home after compact cleanup: $(format_mb "$home_free") free, need $(format_mb "$home_need")"
		fi
	fi
	if [ "$home_free" -lt "$home_need" ]; then
		die "Preflight failed: not enough home space"
	fi
}

copy_executable() {
	src="$1"
	dst="$2"
	if [ -L "$dst" ]; then
    die "destination path is a symlink: $dst"
  fi
  if [ -e "$dst" ] && [ ! -f "$dst" ]; then
    die "destination path is not a regular file: $dst"
  fi
  tmp="$dst.tmp.$$"
  rm -f "$tmp"
  if command -v install >/dev/null 2>&1; then
    if ! install -m 0755 "$src" "$tmp"; then
      rm -f "$tmp"
      return 1
    fi
  else
    if ! cp "$src" "$tmp"; then
      rm -f "$tmp"
      return 1
    fi
    if ! chmod 0755 "$tmp"; then
      rm -f "$tmp"
      return 1
    fi
  fi
  mv "$tmp" "$dst"
}

sha256_file() {
  path="$1"
  if command -v sha256sum >/dev/null 2>&1; then
    sha256sum "$path" | awk '{print $1}'
    return
  fi
  if command -v shasum >/dev/null 2>&1; then
    shasum -a 256 "$path" | awk '{print $1}'
    return
  fi
  die "sha256sum or shasum is required"
}

verify_checksum() {
  checksums="$1"
  artifact="$2"
  artifact_name="$(basename "$artifact")"
  expected="$(awk -v name="$artifact_name" '
    $2 == name || $2 == "*" name || $2 == "./" name { print $1; found = 1; exit }
    END { if (!found) exit 1 }
  ' "$checksums")" || die "CHECKSUMS.sha256 does not list $artifact_name"
  actual="$(sha256_file "$artifact")"
  if [ "$actual" != "$expected" ]; then
    die "checksum mismatch for $artifact_name"
  fi
  ARTIFACT_DIGEST="sha256:$actual"
}

managed_child_dirs() {
  printf '%s\n' \
    "releases" \
    "bin" \
    ".install" \
    "secrets" \
    "skills" \
    "memory" \
    "logs" \
    "cache" \
    "workspace" \
    "backups" \
    "scripts" \
    "system"
}

start_update_lock_perl() {
  lock="$1"
  ready="$2"
  perl -e 'use Fcntl qw(:flock SEEK_SET); my ($lock, $ready) = @ARGV; open my $fh, "+>>", $lock or die "$lock: $!\n"; if (!flock($fh, LOCK_EX | LOCK_NB)) { open my $r, ">", $ready; print $r "held\n" if $r; exit 75; } truncate($fh, 0) or die "$lock: $!\n"; seek($fh, 0, SEEK_SET) or die "$lock: $!\n"; my @g = gmtime(); my $ts = sprintf("%04d-%02d-%02dT%02d:%02d:%02dZ", $g[5] + 1900, $g[4] + 1, $g[3], $g[2], $g[1], $g[0]); print $fh "pid=$$\ncreated_at=$ts\n" or die "$lock: $!\n"; open my $r, ">", $ready or die "$ready: $!\n"; print $r "locked\n"; close $r; $SIG{TERM} = sub { exit 0 }; $SIG{INT} = sub { exit 0 }; sleep 2147483647;' "$lock" "$ready" &
}

start_update_lock_flock() {
  lock="$1"
  ready="$2"
  (
    if ! flock -n 9; then
      printf '%s\n' held >"$ready"
      exit 75
    fi
    : >"$lock"
    printf 'pid=%s\ncreated_at=%s\n' "$$" "$(date -u +%Y-%m-%dT%H:%M:%SZ)" >"$lock"
    printf '%s\n' locked >"$ready"
    exec sleep 2147483647
  ) 9>>"$lock" &
}

start_update_lock_mkdir() {
  lock="$1"
  lock_dir="$lock.dir"
  if ! mkdir "$lock_dir" 2>/dev/null; then
    die "another Anyy install or update is already running: $lock"
  fi
  : >"$lock"
  printf 'pid=%s\ncreated_at=%s\n' "$$" "$(date -u +%Y-%m-%dT%H:%M:%SZ)" >"$lock"
  UPDATE_LOCK_DIR="$lock_dir"
}

wait_update_lock_helper() {
  pid="$1"
  ready="$2"
  lock="$3"
  tries=0
  while [ ! -s "$ready" ]; do
    if ! kill -0 "$pid" 2>/dev/null; then
      wait "$pid" 2>/dev/null || true
      rm -f "$ready"
      UPDATE_LOCK_PID=""
      die "could not acquire update lock: $lock"
    fi
    tries=$((tries + 1))
    if [ "$tries" -ge 5 ]; then
      kill "$pid" 2>/dev/null || true
      wait "$pid" 2>/dev/null || true
      rm -f "$ready"
      UPDATE_LOCK_PID=""
      die "timed out acquiring update lock: $lock"
    fi
    sleep 1
  done
  lock_status="$(cat "$ready" 2>/dev/null || true)"
  case "$lock_status" in
    locked)
      ;;
    held)
      wait "$pid" 2>/dev/null || true
      rm -f "$ready"
      UPDATE_LOCK_PID=""
      die "another Anyy install or update is already running: $lock"
      ;;
    *)
      kill "$pid" 2>/dev/null || true
      wait "$pid" 2>/dev/null || true
      rm -f "$ready"
      UPDATE_LOCK_PID=""
      die "could not acquire update lock: $lock"
      ;;
  esac
}

acquire_update_lock() {
  home="$1"
  ensure_managed_paths_safe "$home"
  lock="$home/.install/update.lock"
  mkdir -p "$home/.install"
  ready="$home/.install/.update.lock.$$"
  rm -f "$ready"
  if command -v perl >/dev/null 2>&1; then
    start_update_lock_perl "$lock" "$ready"
  elif command -v flock >/dev/null 2>&1; then
    start_update_lock_flock "$lock" "$ready"
  else
    start_update_lock_mkdir "$lock"
    UPDATE_LOCK="$lock"
    UPDATE_LOCK_READY="$ready"
    return
  fi
  UPDATE_LOCK_PID="$!"
  wait_update_lock_helper "$UPDATE_LOCK_PID" "$ready" "$lock"
  UPDATE_LOCK="$lock"
  UPDATE_LOCK_READY="$ready"
}

release_update_lock() {
  if [ "${UPDATE_LOCK_PID:-}" ]; then
    kill "$UPDATE_LOCK_PID" 2>/dev/null || true
    wait "$UPDATE_LOCK_PID" 2>/dev/null || true
    UPDATE_LOCK_PID=""
  fi
  if [ "${UPDATE_LOCK_READY:-}" ]; then
    rm -f "$UPDATE_LOCK_READY"
    UPDATE_LOCK_READY=""
  fi
  if [ "${UPDATE_LOCK_DIR:-}" ]; then
    rm -rf "$UPDATE_LOCK_DIR"
    UPDATE_LOCK_DIR=""
  fi
  if [ "${UPDATE_LOCK:-}" ]; then
    UPDATE_LOCK=""
  fi
}

handle_install_exit() {
  anyy_status="$1"
  trap - EXIT HUP INT TERM
  if [ -n "${PREVIOUS_RELEASE_TMP:-}" ]; then
    rm -f "$PREVIOUS_RELEASE_TMP" || true
    PREVIOUS_RELEASE_TMP=
  fi
  if [ -n "${work_dir:-}" ]; then
    rm -rf "$work_dir" || true
    work_dir=
  fi
  release_update_lock
  report_no_activation_on_failure "$anyy_status"
  exit "$anyy_status"
}

handle_install_signal() {
  handle_install_exit "$1"
}

replace_symlink_atomic() {
  src="$1"
  dst="$2"
  if mv -Tf "$src" "$dst" 2>/dev/null; then
    return 0
  fi
  if command -v perl >/dev/null 2>&1; then
    perl -e 'rename $ARGV[0], $ARGV[1] or die "$!\n"' "$src" "$dst"
    return
  fi
  if command -v python3 >/dev/null 2>&1; then
    python3 -c 'import os,sys; os.replace(sys.argv[1], sys.argv[2])' "$src" "$dst"
    return
  fi
  if [ -L "$dst" ]; then
    target="$(readlink "$src")" || return 1
    ln -sfn "$target" "$dst" || return 1
    rm -f "$src"
    return 0
  fi
  if [ ! -e "$dst" ]; then
    mv -f "$src" "$dst"
    return
  fi
  echo "cannot replace $dst: GNU mv -T, python3, perl, or symlink fallback is required" >&2
  return 1
}

activate_release() {
  home="$1"
  version="$2"
  validate_version "$version"
  tmp_link="$home/.current.tmp.$$"
  rm -f "$tmp_link"
  ln -s "releases/$version" "$tmp_link"
  if ! replace_symlink_atomic "$tmp_link" "$home/current"; then
    rm -f "$tmp_link"
    return 1
  fi
  ANYY_RELEASE_ACTIVATED=1
}

link_bin() {
  home="$1"
  tmp_link="$home/bin/.anyy.tmp.$$"
  rm -f "$tmp_link"
  ln -s ../current/anyy "$tmp_link"
  if ! replace_symlink_atomic "$tmp_link" "$home/bin/anyy"; then
    rm -f "$tmp_link"
    return 1
  fi
}

write_source_marker() {
  home="$1"
  method="$2"
  channel="$3"
  version="$4"
  digest="$5"
  validate_version "$version"
  installed_at="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
  marker="$home/.install/source.json"
  ensure_source_marker_path_safe "$home" || return 1
  tmp_marker="$(create_private_temp_file "$home/.install" "source.json.tmp")" || return 1
  if ! cat >"$tmp_marker" <<EOF
{
  "source": "resident",
  "method": "$method",
  "channel": "$channel",
  "version": "$version",
  "artifact_digest": "$digest",
  "installed_at": "$installed_at",
  "managed": false
}
EOF
  then
    rm -f "$tmp_marker"
    return 1
  fi
  if ! mv "$tmp_marker" "$marker"; then
    rm -f "$tmp_marker"
    return 1
  fi
  chmod 600 "$marker" || return 1
}

ensure_source_marker_path_safe() {
  anyy_source_path="$1/.install/source.json"
  if [ -L "$anyy_source_path" ]; then
    return 1
  fi
  if [ -e "$anyy_source_path" ] && [ ! -f "$anyy_source_path" ]; then
    return 1
  fi
}

ensure_managed_child_path_safe() {
  anyy_safe_home="$1"
  anyy_safe_child="$2"
  if [ -L "$anyy_safe_home/$anyy_safe_child" ]; then
    die "$anyy_safe_child path is a symlink: $anyy_safe_home/$anyy_safe_child"
  fi
}

ensure_home_path_safe() {
  anyy_safe_home="$1"
  if [ -L "$anyy_safe_home" ]; then
    die "home path is a symlink: $anyy_safe_home"
  fi
  if [ -e "$anyy_safe_home" ] && [ ! -d "$anyy_safe_home" ]; then
    die "home path is not a directory: $anyy_safe_home"
  fi
}

ensure_managed_paths_safe() {
  anyy_safe_home="$1"
  ensure_home_path_safe "$anyy_safe_home"
  for anyy_safe_child in $(managed_child_dirs); do
    ensure_managed_child_path_safe "$anyy_safe_home" "$anyy_safe_child"
  done
}

prepare_layout() {
  home="$1"
  ensure_home_path_safe "$home"
  mkdir -p "$home"
  chmod 700 "$home"
  ensure_managed_paths_safe "$home"
  for anyy_layout_child in $(managed_child_dirs); do
    dir="$home/$anyy_layout_child"
    mkdir -p "$dir"
    chmod 700 "$dir"
  done
}

validate_install_candidate() {
  anyy_candidate_home="$1"
  anyy_candidate_version="$2"
  anyy_candidate_current="$(current_release_version "$anyy_candidate_home")"
  if [ "$anyy_candidate_version" = "$anyy_candidate_current" ]; then
    die "release is already active: $anyy_candidate_version"
  fi
  anyy_candidate_previous="$(previous_release_version "$anyy_candidate_home")"
  if [ -n "$anyy_candidate_previous" ] && [ "$anyy_candidate_version" = "$anyy_candidate_previous" ]; then
    die "release is the previous rollback target: $anyy_candidate_version"
  fi
}

repair_active_release_install() {
	home="$1"
	anyy_install_version="$2"
	validate_version "$anyy_install_version"
	ensure_home_path_safe "$home"
	ensure_managed_paths_safe "$home"
	prepare_layout "$home"
	link_bin "$home"
	ensure_command_entrypoint "$home"
	release_update_lock
	echo "Anyy $anyy_install_version is already installed."
	print_command_status "$home"
	print_gateway_status "$home"
}

install_binary() {
	home="$1"
	anyy_install_version="$2"
	binary="$3"
  method="$4"
  channel="$5"
  digest="$6"
  validate_version "$anyy_install_version"
  ensure_home_path_safe "$home"
  ensure_managed_paths_safe "$home"
  prepare_layout "$home"
  ensure_managed_paths_safe "$home"
  previous="$(current_release_version "$home")"
  validate_install_candidate "$home" "$anyy_install_version"
  stage_previous_release "$home" "$previous"
  release_dir="$home/releases/$anyy_install_version"
  if [ -L "$release_dir" ]; then
    die "release path is a symlink: $release_dir"
  fi
  mkdir -p "$release_dir"
  chmod 700 "$release_dir"
  copy_executable "$binary" "$release_dir/anyy"
  link_bin "$home"
  activate_release "$home" "$anyy_install_version"
  if ! commit_previous_release "$home"; then
    die "could not update previous release marker after activation"
  fi
  if ! write_source_marker "$home" "$method" "$channel" "$anyy_install_version" "$digest"; then
    echo "install.sh: could not write install source marker" >&2
	fi
}

archive_selected_entry() {
	archive="$1"
	work="$2"
	list_file="$work/.entries.$$"
	verbose_file="$work/.verbose.$$"
	tar -tzf "$archive" >"$list_file"
	tar -tvzf "$archive" >"$verbose_file"
	while IFS= read -r listing; do
		[ -n "$listing" ] || continue
		case "$listing" in
			l* | *' -> '*)
				die "archive contains symlink: $listing"
				;;
			[-d]*)
				;;
			*)
				die "archive contains unsupported entry: $listing"
				;;
		esac
	done <"$verbose_file"
	selected_entry=
	while IFS= read -r entry; do
		case "$entry" in
			"" | -* | /* | ./* | ../* | */../* | *'/..' | . | ..)
				die "archive contains unsafe path: $entry"
				;;
		esac
		case "$entry" in
			*/)
				continue
				;;
			anyy)
				;;
			*/anyy)
				parent="${entry%/anyy}"
				case "$parent" in
					"" | . | */*)
						die "archive contains unsupported anyy path: $entry"
						;;
				esac
				;;
			*)
				die "archive contains unsupported file path: $entry"
				;;
		esac
		if [ -n "$selected_entry" ]; then
			die "archive contains multiple anyy binaries"
		fi
		selected_entry="$entry"
	done <"$list_file"
	[ -n "$selected_entry" ] || die "archive does not contain a anyy executable"
	printf '%s\n' "$selected_entry"
}

archive_entry_size() {
	archive="$1"
	entry="$2"
	tar -tvzf "$archive" "$entry" | awk '
		{
			max = 0
			for (i = 1; i <= NF; i++) {
				if ($i ~ /^[0-9]+$/ && $i > max) {
					max = $i
				}
			}
			if (max > 0) {
				print max
				found = 1
			}
		}
		END {
			if (!found) {
				exit 1
			}
		}
	'
}

extract_archive_entry_to_path() {
	archive="$1"
	entry="$2"
	dst="$3"
	if [ -L "$dst" ]; then
		die "destination path is a symlink: $dst"
	fi
	tmp="$dst.tmp.$$"
	rm -f "$tmp"
	if ! tar -xOzf "$archive" "$entry" >"$tmp"; then
		rm -f "$tmp"
		die "could not extract anyy from archive"
	fi
	if ! chmod 755 "$tmp"; then
		rm -f "$tmp"
		die "could not set executable permissions"
	fi
	if ! mv "$tmp" "$dst"; then
		rm -f "$tmp"
		die "could not install executable"
	fi
}

install_archive_binary() {
	home="$1"
	anyy_install_version="$2"
	archive="$3"
	entry="$4"
	method="$5"
	channel="$6"
	digest="$7"
	validate_version "$anyy_install_version"
	ensure_home_path_safe "$home"
	ensure_managed_paths_safe "$home"
	prepare_layout "$home"
	ensure_managed_paths_safe "$home"
	previous="$(current_release_version "$home")"
	validate_install_candidate "$home" "$anyy_install_version"
	stage_previous_release "$home" "$previous"
	release_dir="$home/releases/$anyy_install_version"
	if [ -L "$release_dir" ]; then
		die "release path is a symlink: $release_dir"
	fi
	mkdir -p "$release_dir"
	chmod 700 "$release_dir"
	extract_archive_entry_to_path "$archive" "$entry" "$release_dir/anyy"
	link_bin "$home"
	activate_release "$home" "$anyy_install_version"
	if ! commit_previous_release "$home"; then
		die "could not update previous release marker after activation"
	fi
	if ! write_source_marker "$home" "$method" "$channel" "$anyy_install_version" "$digest"; then
		echo "install.sh: could not write install source marker" >&2
	fi
}

install_from_artifact() {
	artifact="$1"
	home="$2"
	anyy_artifact_version="${VERSION:-dev}"
  validate_version "$anyy_artifact_version"
  [ -f "$artifact" ] || die "artifact not found: $artifact"
  if digest_value="$(sha256_file "$artifact" 2>/dev/null)"; then
    digest="sha256:$digest_value"
  else
    digest="sha256:unknown"
  fi
  trap 'anyy_status=$?; handle_install_exit "$anyy_status"' EXIT
  trap 'handle_install_signal 129' HUP
  trap 'handle_install_signal 130' INT
  trap 'handle_install_signal 143' TERM
  acquire_update_lock "$home"
  log_step "Installing to $home..."
  install_binary "$home" "$anyy_artifact_version" "$artifact" "local" "dev" "$digest"
  ensure_command_entrypoint "$home"
  release_update_lock
  echo "Installed Anyy $anyy_artifact_version."
  print_command_status "$home"
  print_gateway_status "$home"
}

download() {
  url="$1"
  path="$2"
  attempt=1
  while [ "$attempt" -le 3 ]; do
    rm -f "$path"
    if [ "${ANYY_QUIET:-0}" = "1" ] || [ ! -t 2 ]; then
      if curl -fsSL "$url" -o "$path"; then
        return 0
      else
        status="$?"
      fi
    elif curl -fL --progress-bar "$url" -o "$path"; then
      return 0
    else
      status="$?"
    fi
    rm -f "$path"
    if [ "$attempt" -ge 3 ]; then
      return "$status"
    fi
    attempt=$((attempt + 1))
    echo "Download failed; retrying ($attempt/3)..." >&2
    sleep 1
  done
  return 1
}

download_quiet() {
	url="$1"
	path="$2"
	curl -fsSL "$url" -o "$path"
}

release_artifact_size() {
	url="$1"
	size="$(curl -fsIL "$url" | awk '
		BEGIN { value = "" }
		tolower($1) == "content-length:" {
			value = $2
			gsub("\r", "", value)
		}
		END { print value }
	')"
	case "$size" in
		"" | *[!0-9]*)
			return 1
			;;
	esac
	printf '%s\n' "$size"
}

create_release_work_dir() {
	parent="$1"
	mkdir -p "$parent"
	mktemp -d "$parent/anyy-install.XXXXXX"
}

link_command_entrypoint() {
	target="$1"
	link="$2"
	if [ -e "$link" ] || [ -L "$link" ]; then
		if [ -L "$link" ]; then
			link_target="$(readlink "$link" 2>/dev/null || true)"
			if [ "$link_target" = "$target" ]; then
				return 0
			fi
			if [ ! -e "$link" ]; then
				rm -f "$link" || return 1
				ln -s "$target" "$link"
				return
			fi
		fi
		echo "Command entrypoint already exists and was not replaced: $link"
		return 1
	fi
	ln -s "$target" "$link"
}

root_command_dir() {
	for dir in /usr/local/bin /opt/homebrew/bin /usr/bin; do
		if [ -d "$dir" ] && [ -w "$dir" ]; then
      printf '%s\n' "$dir"
      return
    fi
  done
  printf '%s\n' ""
}

ensure_command_entrypoint() {
  home="$1"
	if [ "$(id -u)" = "0" ]; then
		if [ "${LINK_USR_BIN:-auto}" != "0" ]; then
			root_bin="$(root_command_dir)"
			if [ -n "$root_bin" ]; then
				link_command_entrypoint "$home/bin/anyy" "$root_bin/anyy" 2>/dev/null || true
			fi
		fi
		return
	fi
  if [ -z "${HOME:-}" ]; then
    return
  fi
	user_bin="$HOME/.local/bin"
	mkdir -p "$user_bin" 2>/dev/null || return
	link_command_entrypoint "$home/bin/anyy" "$user_bin/anyy" 2>/dev/null || true
}

print_command_status() {
  home="$1"
  command_path="$(command -v anyy 2>/dev/null || true)"
  if command_matches_anyy "$home" "$command_path"; then
    echo "Command: anyy"
    return
  fi
  echo "Binary: $home/bin/anyy"
  if [ -n "$command_path" ]; then
    echo "Command on PATH does not point to this install: $command_path"
  else
    echo "Command not found on PATH yet."
  fi
  if [ "$(id -u)" != "0" ] && [ -n "${HOME:-}" ]; then
    echo "To enable it, add this directory to PATH: $HOME/.local/bin"
  elif root_bin="$(root_command_dir)" && [ -n "$root_bin" ]; then
    echo "To enable it, add this directory to PATH: $root_bin"
  else
    echo "To enable it, add this directory to PATH: $home/bin"
  fi
}

print_gateway_status() {
  home="$1"
  resident_binary="$home/bin/anyy"
  if [ ! -x "$resident_binary" ]; then
    echo "Gateway: status unavailable"
    return
  fi
  gateway_output="$("$resident_binary" gateway status --home "$home" 2>/dev/null)" || {
    echo "Gateway: status unavailable"
    return
  }
  gateway_line="$(printf '%s\n' "$gateway_output" | sed -n '1p')"
  case "$gateway_line" in
    Gateway:\ *)
      echo "$gateway_line"
      ;;
    *)
      echo "Gateway: status unavailable"
      ;;
  esac
}

command_matches_anyy() {
  home="$1"
  command_path="$2"
  expected="$home/bin/anyy"
  [ -n "$command_path" ] || return 1
  [ "$command_path" = "$expected" ] && return 0
  if [ -L "$command_path" ] && command -v readlink >/dev/null 2>&1; then
    target="$(readlink "$command_path" 2>/dev/null || true)"
    case "$target" in
      "$expected")
        return 0
        ;;
      /*)
        [ "$target" = "$expected" ] && return 0
        ;;
      *)
        command_dir="${command_path%/*}"
        [ "$command_dir/$target" = "$expected" ] && return 0
        ;;
    esac
  fi
  return 1
}

extract_anyy_binary() {
  archive="$1"
  dest="$2"
  rm -rf "$dest"
  mkdir -p "$dest"
  list_file="$dest/.entries.$$"
  verbose_file="$dest/.verbose.$$"
  extract_dir="$dest/.extract.$$"
  tar -tzf "$archive" >"$list_file"
  tar -tvzf "$archive" >"$verbose_file"
  while IFS= read -r listing; do
    [ -n "$listing" ] || continue
    case "$listing" in
      l* | *' -> '*)
        die "archive contains symlink: $listing"
        ;;
      [-d]*)
        ;;
      *)
        die "archive contains unsupported entry: $listing"
        ;;
    esac
  done <"$verbose_file"
  selected_entry=
  while IFS= read -r entry; do
    case "$entry" in
      "" | -* | /* | ./* | ../* | */../* | *'/..' | . | ..)
        die "archive contains unsafe path: $entry"
        ;;
    esac
    case "$entry" in
      */)
        continue
        ;;
      anyy)
        ;;
      */anyy)
        parent="${entry%/anyy}"
        case "$parent" in
          "" | . | */*)
            die "archive contains unsupported anyy path: $entry"
            ;;
        esac
        ;;
      *)
        die "archive contains unsupported file path: $entry"
        ;;
    esac
    if [ -n "$selected_entry" ]; then
      die "archive contains multiple anyy binaries"
    fi
    selected_entry="$entry"
  done <"$list_file"
  [ -n "$selected_entry" ] || die "archive does not contain a anyy executable"
  mkdir -p "$extract_dir"
  tar -xzf "$archive" -C "$extract_dir" "$selected_entry"
  candidate="$extract_dir/$selected_entry"
  [ -f "$candidate" ] || die "archive selected anyy is not a regular file"
  copy_executable "$candidate" "$dest/anyy"
  printf '%s\n' "$dest/anyy"
}

install_from_release() {
  home="$1"
  detect_os_arch >/dev/null
  log_step "Checking Anyy install..."
  require_command curl
  require_command tar
  require_gzip
  require_command awk
  require_command mktemp
  require_command readlink
  require_checksum_command
  work_dir=
  trap 'anyy_status=$?; handle_install_exit "$anyy_status"' EXIT
  trap 'handle_install_signal 129' HUP
  trap 'handle_install_signal 130' INT
  trap 'handle_install_signal 143' TERM
  acquire_update_lock "$home"
  anyy_release_version="$(resolve_latest_version)"
  log_step "Latest: $anyy_release_version"
  log_step "Home: $home"
  log_step "Platform: $os/$arch"
	if [ "$anyy_release_version" = "$(current_release_version "$home")" ]; then
		repair_active_release_install "$home" "$anyy_release_version"
		return
	fi
	validate_install_candidate "$home" "$anyy_release_version"
	artifact_name="anyy_${anyy_release_version}_${os}_${arch}.tar.gz"
	release_url="$ANYY_RELEASE_BASE_URL/$anyy_release_version"
	archive_url="$release_url/$artifact_name"
	archive_need="$(release_artifact_size "$archive_url")" || die "Preflight failed: could not determine release artifact size"
	run_release_download_preflight "$home" "$archive_need" "$ANYY_INSTALL_COMPACT"
	work_dir="$(create_release_work_dir "$RELEASE_WORK_PARENT")"
	printf '%s\n' "$$" >"$work_dir/$INSTALL_TEMP_MARKER" || die "could not mark install temp directory"
	archive="$work_dir/$artifact_name"
	checksums="$work_dir/CHECKSUMS.sha256"
	log_step "Downloading Anyy $anyy_release_version ($os/$arch)..."
	download "$archive_url" "$archive"
	download_quiet "$release_url/CHECKSUMS.sha256" "$checksums"
	log_step "Verifying checksum..."
	verify_checksum "$checksums" "$archive"
	selected_entry="$(archive_selected_entry "$archive" "$work_dir")"
	binary_need="$(archive_entry_size "$archive" "$selected_entry")" || die "Preflight failed: could not determine release binary size"
	run_release_install_preflight "$home" "$binary_need" "$ANYY_INSTALL_COMPACT"
	log_step "Installing to $home..."
	install_archive_binary "$home" "$anyy_release_version" "$archive" "$selected_entry" "curl" "stable" "$ARTIFACT_DIGEST"
	ensure_command_entrypoint "$home"
	release_update_lock
	echo "Installed Anyy $anyy_release_version."
  print_command_status "$home"
  print_gateway_status "$home"
}

usage() {
  echo "usage: scripts/install.sh [/path/to/anyy-binary]" >&2
  ANYY_USAGE_EXIT=1
  exit 2
}

ANYY_HOME="$(resolve_home)"
ARTIFACT="${1:-}"

if [ "$#" -gt 1 ]; then
  usage
fi

if [ -n "$ARTIFACT" ]; then
  install_from_artifact "$ARTIFACT" "$ANYY_HOME"
else
  install_from_release "$ANYY_HOME"
fi
