#!/bin/sh
set -eu

log() {
  printf '%s\n' "$*" >&2
}

usage() {
  cat <<'USAGE'
usage: curl -fsSL https://ctx.rs/install | sh
       curl -fsSL https://ctx.rs/install | sh -s -- --no-setup

Installs the ctx CLI from signed release metadata, installs the bundled
agent-history skill, then runs ctx setup to index discovered local agent
history.

Prerequisites:
  curl, OpenSSL, install, mktemp, awk, date, uname

Options:
  --no-setup           Install only; do not install the skill or run ctx setup
                       unless a skill option is also passed.
  --no-skill           Do not install the bundled ctx agent skill.
  --skill-agent AGENT  Install the skill into a specific agent skill dir.
                       Repeat for multiple agents.
  --all-skill-agents   Install the skill into all supported agent skill dirs.
  --no-modify-path     Do not update shell startup files when the install
                       directory is not on PATH.
  --no-man             Do not install generated man pages.
  --man-dir D          Man page directory. Defaults to $HOME/.local/share/man/man1.
  -h, --help           Show this help.

Environment:
  CTX_INSTALL_NO_SETUP=1             Install only; do not install the skill or run ctx setup
                                     unless a skill option is also passed.
  CTX_INSTALL_NO_SKILL=1             Do not install the bundled ctx agent skill.
  CTX_INSTALL_SKILL_AGENTS=codex,... Install the skill into specific agent dirs.
  CTX_INSTALL_ALL_SKILL_AGENTS=1     Install the skill into all supported agent dirs.
  CTX_INSTALL_NO_MODIFY_PATH=1       Do not update shell startup files.
  CTX_INSTALL_NO_MAN=1               Do not install generated man pages.
  CTX_MAN_DIR=$HOME/.local/share/man/man1
                                     Override man page install directory.
  CTX_SETUP_PROGRESS=auto            Setup progress mode: auto, plain, or none.
  CTX_ANALYTICS_OFF=1                Disable CLI analytics during setup.
  CTX_INSTALL_DIAGNOSTICS_OFF=1      Disable installer diagnostic stage reports.
  CTX_INSTALL_ATTEMPT_ID=ia_...      Override installer attempt ID for tests.
  CTX_ALLOW_CUSTOM_RELEASE_BASE_URL=1
                                     Allow non-cli.ctx.rs artifact metadata for development.
  CTX_RELEASE_METADATA_SIGNATURE_URL Override detached metadata signature URL.
USAGE
}

fail() {
  log "error: $*"
  exit 1
}

need_cmd() {
  command -v "$1" >/dev/null 2>&1 || fail "missing required command: $1"
}

append_skill_agent() {
  agent="$1"
  test -n "$agent" || fail "--skill-agent requires a value"
  case "$agent" in
    *'
'*) fail "invalid skill agent: $agent" ;;
  esac
  if [ -n "$skill_agents" ]; then
    skill_agents="$skill_agents
$agent"
  else
    skill_agents="$agent"
  fi
}

functions_base="${CTX_FUNCTIONS_BASE:-https://cli.ctx.rs/functions/v1}"
channel="${CTX_CHANNEL:-stable}"
install_attempt_id="${CTX_INSTALL_ATTEMPT_ID:-ia_tR2Zi7hkwq3ENmXDnILWW56T}"
metadata_url="${CTX_RELEASE_METADATA_URL:-${functions_base%/}/releases/$channel/ctx-release-metadata.env}"
metadata_signature_url="${CTX_RELEASE_METADATA_SIGNATURE_URL:-$metadata_url.sig}"
bin_dir="${CTX_BIN_DIR:-${HOME:-}/.local/bin}"
man_dir="${CTX_MAN_DIR:-${HOME:-}/.local/share/man/man1}"
run_setup=1
run_skill=1
modify_path=1
no_skill_requested=0
explicit_skill_request=0
all_skill_agents=0
skill_agents=
install_man=1
installer_error_kind="exit"

while [ "$#" -gt 0 ]; do
  case "$1" in
    --no-setup)
      run_setup=0
      ;;
    --no-skill)
      run_skill=0
      no_skill_requested=1
      ;;
    --skill-agent)
      shift
      append_skill_agent "${1:-}"
      explicit_skill_request=1
      ;;
    --all-skill-agents)
      all_skill_agents=1
      explicit_skill_request=1
      ;;
    --no-modify-path)
      modify_path=0
      ;;
    --no-man)
      install_man=0
      ;;
    --man-dir)
      shift
      man_dir="${1:-}"
      ;;
    -h|--help)
      usage
      exit 0
      ;;
    *)
      fail "unknown argument: $1"
      ;;
  esac
  shift
done

test -n "$bin_dir" || fail "CTX_BIN_DIR is empty and HOME is unavailable"
test -n "$man_dir" || fail "CTX_MAN_DIR is empty and --man-dir was not provided"

need_cmd awk
need_cmd curl
need_cmd date
need_cmd install
need_cmd mktemp
need_cmd openssl
need_cmd uname

detect_platform() {
  os="$(uname -s 2>/dev/null || printf unknown)"
  arch="$(uname -m 2>/dev/null || printf unknown)"
  case "$os:$arch" in
    Linux:x86_64|Linux:amd64) printf 'linux-x64' ;;
    Linux:aarch64|Linux:arm64) printf 'linux-aarch64' ;;
    Darwin:arm64|Darwin:aarch64) printf 'macos-arm64' ;;
    Darwin:x86_64|Darwin:amd64) printf 'macos-x64' ;;
    FreeBSD:x86_64|FreeBSD:amd64) printf 'freebsd-x64' ;;
    *) return 1 ;;
  esac
}

download_file() {
  url="$1"
  dest="$2"
  case "$url" in
    https://*) ;;
    *) fail "refusing non-HTTPS download URL: $url" ;;
  esac
  curl --proto '=https' --tlsv1.2 -fsSL --retry 3 --connect-timeout 20 "$url" -o "$dest"
}

download_release_artifact() {
  raw_url="$1"
  raw_dest="$2"
  gzip_url="$raw_url.gz"
  gzip_dest="$raw_dest.gz"
  artifact_transport_url="$raw_url"
  artifact_compression="identity"

  if command -v gzip >/dev/null 2>&1; then
    if curl --proto '=https' --tlsv1.2 -fsSL --retry 3 --connect-timeout 20 "$gzip_url" -o "$gzip_dest"; then
      if ! gzip -t "$gzip_dest" >/dev/null 2>&1; then
        installer_error_kind="decompression_failed"
        fail "invalid gzip release artifact: $gzip_url"
      fi
      if ! gzip -dc "$gzip_dest" >"$raw_dest"; then
        installer_error_kind="decompression_failed"
        fail "could not decompress release artifact: $gzip_url"
      fi
      artifact_transport_url="$gzip_url"
      artifact_compression="gzip"
      return 0
    fi
    rm -f "$gzip_dest"
  fi

  download_file "$raw_url" "$raw_dest"
}

write_metadata_public_key() {
  cat >"$1" <<'CTX_METADATA_PUBLIC_KEY'
-----BEGIN PUBLIC KEY-----
MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAyBPNIx3H/NwWlN9CPHY5
kOEe9kQEshOJEMpv3Atq086H1FWqliTm3BCWiO4s/89wNMn11Pla2JetCWNiWsbx
m3BIxCd1o6cq8y9ur6Zk1RGOQBLQgqhFm5BpcTTavhtlc3FdV2KSm2UU1IEJAiFX
JyMlbgmf3tXfO8Cji/3mG11rWCXfnEzXJmig5/WWA21ZgsafPJGH9ow7FsLok5G1
kvOeVDXcv0gzmxWH+2O40kCGWo7BK7P/2DPD2GbXc81Mf6S7vWi7CeFiBeGH8EGZ
6MgBM0UnAFEqtx/WvY47O+LHzFrGlJTpss3xlxsSQOTmXDJdOzmQVi04GkbOtBEl
+dIyYsxZGusLBMGDqkZekO4Z5LvqA8zHt4JAElZCs8SGTlV70MSlnyZb5/rkKx9k
Mvb7YjuYbY6vnN5Pp3P7gMhOKehP+62U80cgyj1m6Sk5bByrs54ne2mM+cwNXXgK
p5UntmkefDcfKP7MmISy93U/kg3fWojE/a+X6TNV/k5fAgMBAAE=
-----END PUBLIC KEY-----
CTX_METADATA_PUBLIC_KEY
}

verify_release_metadata_signature() {
  metadata_path="$1"
  signature_path="$2"
  public_key_path="$3"
  raw_signature_path="$tmp_dir/metadata.sig.raw"

  if ! openssl enc -A -d -base64 -in "$signature_path" -out "$raw_signature_path" 2>/dev/null; then
    fail "metadata signature is not base64-encoded RSA-SHA256 bytes"
  fi
  [ -s "$raw_signature_path" ] || fail "metadata signature is empty"
  if ! openssl dgst -sha256 -verify "$public_key_path" -signature "$raw_signature_path" "$metadata_path" >/dev/null 2>&1; then
    fail "metadata signature verification failed"
  fi
}

metadata_value() {
  file="$1"
  key="$2"
  awk -F= -v key="$key" '
    $0 ~ /^[[:space:]]*#/ { next }
    $1 == key { print substr($0, length(key) + 2); found = 1; exit }
    END { if (!found) exit 1 }
  ' "$file"
}

metadata_value_optional() {
  file="$1"
  key="$2"
  metadata_value "$file" "$key" 2>/dev/null || true
}

validate_safe_value() {
  name="$1"
  value="$2"
  case "$value" in
    *'
'*|*'..'*|*'/'*|*'\'*) fail "unsafe $name: $value" ;;
  esac
}

path_contains_dir() {
  needle="${1%/}"
  old_ifs="$IFS"
  IFS=:
  for entry in ${PATH:-}; do
    if [ "${entry%/}" = "$needle" ]; then
      IFS="$old_ifs"
      return 0
    fi
  done
  IFS="$old_ifs"
  return 1
}

profile_has_path_line() {
  profile="$1"
  needle="$2"
  [ -f "$profile" ] || return 1
  awk -v needle="$needle" '
    $0 ~ /^[[:space:]]*#/ { next }
    index($0, needle) && ($0 ~ /PATH/ || $0 ~ /fish_user_paths/ || $0 ~ /fish_add_path/) {
      found = 1
      exit
    }
    END { exit found ? 0 : 1 }
  ' "$profile"
}

shell_double_quote_escape() {
  printf '%s' "$1" | sed 's/\\/\\\\/g; s/"/\\"/g; s/`/\\`/g; s/\$/\\$/g'
}

path_setup_profile() {
  shell_name="$1"
  test -n "${HOME:-}" || return 1

  case "$shell_name" in
    fish)
      printf '%s/.config/fish/config.fish\n' "$HOME"
      ;;
    zsh)
      printf '%s/.zshrc\n' "${ZDOTDIR:-$HOME}"
      ;;
    bash)
      if [ -f "$HOME/.bashrc" ]; then
        printf '%s/.bashrc\n' "$HOME"
      elif [ -f "$HOME/.bash_profile" ]; then
        printf '%s/.bash_profile\n' "$HOME"
      elif [ -f "$HOME/.profile" ]; then
        printf '%s/.profile\n' "$HOME"
      else
        case "$platform" in
          macos-*) printf '%s/.bash_profile\n' "$HOME" ;;
          *) printf '%s/.bashrc\n' "$HOME" ;;
        esac
      fi
      ;;
    *)
      printf '%s/.profile\n' "$HOME"
      ;;
  esac
}

profile_contains_path_setup() {
  profile="$1"
  dir="${2%/}"
  profile_has_path_line "$profile" "$dir" && return 0
  dir_escaped="$(shell_double_quote_escape "$dir")"
  profile_has_path_line "$profile" "$dir_escaped" && return 0

  if [ -n "${HOME:-}" ]; then
    home_prefix="${HOME%/}/"
    case "$dir" in
      "$home_prefix"*)
        rel="${dir#"$home_prefix"}"
        profile_has_path_line "$profile" "\$HOME/$rel" && return 0
        profile_has_path_line "$profile" "~/$rel" && return 0
        ;;
    esac
  fi

  return 1
}

path_setup_snippet() {
  shell_name="$1"
  dir_escaped="$(shell_double_quote_escape "$2")"

  case "$shell_name" in
    fish)
      cat <<EOF

# ctx installer PATH setup
if not contains -- "$dir_escaped" \$PATH
    set -gx PATH "$dir_escaped" \$PATH
end
EOF
      ;;
    *)
      cat <<EOF

# ctx installer PATH setup
case ":\${PATH}:" in
  *":$dir_escaped:"*) ;;
  *) export PATH="$dir_escaped:\${PATH}" ;;
esac
EOF
      ;;
  esac
}

print_current_path_command() {
  shell_name="$1"
  dir_escaped="$(shell_double_quote_escape "$2")"

  case "$shell_name" in
    fish)
      printf '  set -gx PATH "%s" $PATH\n' "$dir_escaped" >&2
      ;;
    *)
      printf '  export PATH="%s:${PATH}"\n' "$dir_escaped" >&2
      ;;
  esac
}

configure_path_if_needed() {
  dir="${bin_dir%/}"
  if path_contains_dir "$dir"; then
    return 0
  fi

  shell_name="${SHELL:-}"
  shell_name="${shell_name##*/}"
  [ -n "$shell_name" ] || shell_name="sh"

  if [ "$modify_path" != "1" ]; then
    log ""
    log "$dir is not on PATH; shell startup file update skipped."
    log "For this shell session, run:"
    print_current_path_command "$shell_name" "$dir"
    return 0
  fi

  if [ -n "${GITHUB_PATH:-}" ]; then
    printf '%s\n' "$dir" >>"$GITHUB_PATH"
    log ""
    log "Added $dir to GITHUB_PATH for later GitHub Actions steps."
    return 0
  fi

  if [ "${CI:-}" = "1" ] || [ "${CI:-}" = "true" ]; then
    log ""
    log "$dir is not on PATH; CI detected, not editing shell startup files."
    log "For this shell session, run:"
    print_current_path_command "$shell_name" "$dir"
    return 0
  fi

  if ! profile="$(path_setup_profile "$shell_name")"; then
    log ""
    log "$dir is not on PATH; HOME is unavailable, so no shell startup file was updated."
    log "For this shell session, run:"
    print_current_path_command "$shell_name" "$dir"
    return 0
  fi

  log ""
  if profile_contains_path_setup "$profile" "$dir"; then
    log "Found existing PATH setup for $dir in $profile."
  else
    profile_dir="$(dirname "$profile")"
    if mkdir -p "$profile_dir" && path_setup_snippet "$shell_name" "$dir" >>"$profile"; then
      log "Added ctx PATH setup to $profile."
    else
      log "warning: could not update shell startup file $profile"
    fi
  fi

  log "$dir is not on the current PATH; restart your shell or run:"
  print_current_path_command "$shell_name" "$dir"
  log "Then verify with:"
  log "  ctx status"
}

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

json_escape() {
  printf '%s' "$1" | sed 's/\\/\\\\/g; s/"/\\"/g'
}

skill_agent_list() {
  joined=
  old_ifs="$IFS"
  IFS='
'
  for agent in $skill_agents; do
    if [ -n "$joined" ]; then
      joined="$joined,$agent"
    else
      joined="$agent"
    fi
  done
  IFS="$old_ifs"
  printf '%s' "$joined"
}

run_skill_install() {
  set -- integrations install skills
  if [ "$all_skill_agents" = "1" ]; then
    set -- "$@" --all-agents
  elif [ -n "$skill_agents" ]; then
    old_ifs="$IFS"
    IFS='
'
    for agent in $skill_agents; do
      set -- "$@" --agent "$agent"
    done
    IFS="$old_ifs"
  fi
  "$install_path" "$@"
}

report_install_stage() {
  stage="$1"
  status="${2:-ok}"
  error_kind="${3:-}"
  [ "${CTX_ANALYTICS_OFF:-0}" = "1" ] && return 0
  [ "${CTX_INSTALL_DIAGNOSTICS_OFF:-0}" = "1" ] && return 0
  command -v curl >/dev/null 2>&1 || return 0
  case "$functions_base" in
    https://*) ;;
    *) return 0 ;;
  esac

  report_channel="${release_channel-$channel}"
  report_version="${version-}"
  payload='{"install_attempt_id":"'"$(json_escape "$install_attempt_id")"'","stage":"'"$(json_escape "$stage")"'","status":"'"$(json_escape "$status")"'","error_kind":"'"$(json_escape "$error_kind")"'","platform":"'"$(json_escape "${platform-}")"'","channel":"'"$(json_escape "$report_channel")"'","version":"'"$(json_escape "$report_version")"'"}'
  curl -fsS -m 2 -H "content-type: application/json" -X POST --data "$payload" "${functions_base%/}/install-attempt" >/dev/null 2>&1 || true
  return 0
}

write_install_marker() {
  marker_path="$install_path.install.json"
  installed_at="$(date -u '+%Y-%m-%dT%H:%M:%SZ')"
  tmp_marker="$marker_path.$$"
  cat >"$tmp_marker" <<EOF
{
  "schema_version": 1,
  "manager": "ctx-hosted-installer",
  "install_attempt_id": "$(json_escape "$install_attempt_id")",
  "install_path": "$(json_escape "$install_path")",
  "platform": "$(json_escape "$platform")",
  "channel": "$(json_escape "$release_channel")",
  "version": "$(json_escape "$version")",
  "sha256": "$(json_escape "$actual_checksum")",
  "metadata_url": "$(json_escape "$metadata_url")",
  "artifact_url": "$(json_escape "$artifact_url")",
  "source_commit": "$(json_escape "$source_commit")",
  "published_at": "$(json_escape "$published_at")",
  "installed_at": "$(json_escape "$installed_at")"
  }
EOF
  mv "$tmp_marker" "$marker_path"
}

platform="${CTX_PLATFORM:-}"
if [ -z "$platform" ]; then
  platform="$(detect_platform)" || fail "cannot detect this host platform; set CTX_PLATFORM"
fi

case "$platform" in
  linux-x64|linux-aarch64|macos-arm64|macos-x64|freebsd-x64) ;;
  *) fail "unsupported platform: $platform" ;;
esac

report_install_stage "script_started" "started" ""

tmp_dir="$(mktemp -d "${TMPDIR:-/tmp}/ctx-cli-install.XXXXXX")"
cleanup() {
  status="$?"
  trap - EXIT INT TERM
  if [ "$status" -ne 0 ]; then
    report_install_stage "installer_failed" "failed" "${installer_error_kind:-exit_$status}"
  fi
  rm -rf "$tmp_dir"
  exit "$status"
}
trap cleanup EXIT
trap 'installer_error_kind="interrupted"; exit 130' INT
trap 'installer_error_kind="terminated"; exit 143' TERM

metadata_file="$tmp_dir/metadata.env"
metadata_signature_file="$tmp_dir/metadata.env.sig"
metadata_public_key_file="$tmp_dir/metadata-public-key.pem"
artifact_path="$tmp_dir/ctx"
download_file "$metadata_url" "$metadata_file"
download_file "$metadata_signature_url" "$metadata_signature_file"
write_metadata_public_key "$metadata_public_key_file"
verify_release_metadata_signature "$metadata_file" "$metadata_signature_file" "$metadata_public_key_file"

schema_version="$(metadata_value "$metadata_file" CTX_RELEASE_SCHEMA_VERSION)" || fail "metadata missing CTX_RELEASE_SCHEMA_VERSION"
version="$(metadata_value "$metadata_file" CTX_RELEASE_VERSION)" || fail "metadata missing CTX_RELEASE_VERSION"
base_url="$(metadata_value "$metadata_file" CTX_RELEASE_BASE_URL)" || fail "metadata missing CTX_RELEASE_BASE_URL"
platform_key="$(printf '%s\n' "$platform" | tr '-' '_')"
artifact="$(metadata_value "$metadata_file" "CTX_RELEASE_ARTIFACT_$platform_key")" || fail "metadata missing artifact for $platform"
checksum="$(metadata_value "$metadata_file" "CTX_RELEASE_SHA256_$platform_key")" || fail "metadata missing checksum for $platform"
release_channel="$(metadata_value_optional "$metadata_file" CTX_RELEASE_CHANNEL)"
source_commit="$(metadata_value_optional "$metadata_file" CTX_RELEASE_SOURCE_COMMIT)"
published_at="$(metadata_value_optional "$metadata_file" CTX_RELEASE_PUBLISHED_AT)"
[ -n "$release_channel" ] || release_channel="$channel"

[ "$schema_version" = "1" ] || fail "unsupported metadata schema: $schema_version"
[ "$release_channel" = "$channel" ] || fail "metadata channel $release_channel does not match requested channel $channel"
case "$base_url" in https://*) ;; *) fail "metadata base URL must be HTTPS" ;; esac
case "$base_url" in
  https://cli.ctx.rs/storage/v1/object/public/releases/artifacts/*) ;;
  *)
    [ "${CTX_ALLOW_CUSTOM_RELEASE_BASE_URL:-0}" = "1" ] || fail "metadata base URL must be under https://cli.ctx.rs/storage/v1/object/public/releases/artifacts/"
    ;;
esac
case "$checksum" in
  [0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]) ;;
  *) fail "checksum for $platform is not a SHA-256 hex digest" ;;
esac
[ "$checksum" != "0000000000000000000000000000000000000000000000000000000000000000" ] || fail "checksum for $platform is a placeholder"
validate_safe_value "artifact name" "$artifact"

artifact_url="${base_url%/}/$artifact"
install_path="${bin_dir%/}/ctx"

if [ "${CTX_INSTALL_NO_MAN:-0}" = "1" ]; then
  install_man=0
fi

if [ "${CTX_INSTALL_NO_MODIFY_PATH:-0}" = "1" ]; then
  modify_path=0
fi

if [ "${CTX_INSTALL_NO_SETUP:-0}" = "1" ]; then
  run_setup=0
fi

if [ "${CTX_INSTALL_ALL_SKILL_AGENTS:-0}" = "1" ]; then
  all_skill_agents=1
  explicit_skill_request=1
fi

if [ -n "${CTX_INSTALL_SKILL_AGENTS:-}" ]; then
  explicit_skill_request=1
  old_ifs="$IFS"
  IFS=,
  for raw_agent in $CTX_INSTALL_SKILL_AGENTS; do
    agent="$(printf '%s' "$raw_agent" | tr -d '[:space:]')"
    if [ -n "$agent" ]; then
      append_skill_agent "$agent"
    fi
  done
  IFS="$old_ifs"
fi

if [ "${CTX_INSTALL_NO_SKILL:-0}" = "1" ]; then
  run_skill=0
  no_skill_requested=1
fi

if [ "$no_skill_requested" = "1" ] && [ "$explicit_skill_request" = "1" ]; then
  fail "cannot combine --no-skill or CTX_INSTALL_NO_SKILL=1 with skill agent options"
fi

if [ "$all_skill_agents" = "1" ] && [ -n "$skill_agents" ]; then
  fail "cannot combine --all-skill-agents with --skill-agent or CTX_INSTALL_SKILL_AGENTS"
fi

if [ "$run_setup" != "1" ] && [ "$explicit_skill_request" != "1" ]; then
  run_skill=0
fi

log "Installing ctx $version ($platform)"
log "  binary: $install_path"
if [ "$run_skill" = "1" ]; then
  if [ "$all_skill_agents" = "1" ]; then
    log "  skill: all supported agents"
  elif [ -n "$skill_agents" ]; then
    log "  skill: $(skill_agent_list)"
  else
    log "  skill: universal + detected agent folders"
  fi
else
  log "  skill: skipped"
fi
if [ "$run_setup" = "1" ]; then
  log "  history: index discovered sessions"
else
  log "  history: skipped"
fi

report_install_stage "artifact_download_started" "started" ""
download_release_artifact "$artifact_url" "$artifact_path"
report_install_stage "artifact_download_completed" "completed" ""
if [ "$artifact_compression" = "gzip" ]; then
  log "Downloaded gzip-compressed artifact."
fi
actual_checksum="$(sha256_file "$artifact_path")"
if [ "$(printf '%s' "$actual_checksum" | tr 'A-F' 'a-f')" != "$(printf '%s' "$checksum" | tr 'A-F' 'a-f')" ]; then
  installer_error_kind="checksum_mismatch"
  fail "checksum mismatch for $artifact: expected $checksum, got $actual_checksum"
fi

mkdir -p "$bin_dir"
install -m 0755 "$artifact_path" "$install_path"
write_install_marker
report_install_stage "binary_installed" "completed" ""

if [ "$install_man" = "1" ]; then
  mkdir -p "$man_dir"
  if "$install_path" docs man --out "$man_dir" >/dev/null; then
    :
  else
    log "warning: failed to install ctx man pages to $man_dir"
  fi
fi

log ""
log "Installed ctx binary."

if [ "$run_skill" = "1" ]; then
  log ""
  report_install_stage "skill_launched" "started" ""
  if run_skill_install; then
    report_install_stage "skill_exited" "completed" ""
  else
    report_install_stage "skill_exited" "failed" "skill_failed"
    log "warning: ctx integrations install skills failed after install; run $install_path integrations install skills to retry"
  fi
else
  log ""
  log "Agent skill skipped. Run $install_path integrations install skills to install it later."
  report_install_stage "skill_skipped" "skipped" ""
fi

setup_status=0
if [ "$run_setup" = "1" ]; then
  setup_progress="${CTX_SETUP_PROGRESS:-auto}"
  log ""
  log "Indexing local agent history..."
  report_install_stage "setup_launched" "started" ""
  "$install_path" setup --progress "$setup_progress" || {
    setup_status="$?"
    installer_error_kind="setup_failed"
    report_install_stage "setup_exited" "failed" "setup_failed"
    log "warning: ctx setup failed after install; run $install_path setup --progress $setup_progress to retry"
  }
  if [ "$setup_status" = "0" ]; then
    report_install_stage "setup_exited" "completed" ""
  fi
else
  log ""
  log "Setup skipped. Run $install_path setup to index local history."
  report_install_stage "setup_skipped" "skipped" ""
fi

configure_path_if_needed

if [ "$setup_status" != "0" ]; then
  exit "$setup_status"
fi
