#!/usr/bin/env sh
set -eu

program="concrete-install"
base_url="${CONCRETE_INSTALL_BASE_URL:-https://install.concrete-security.com}"
version="${CONCRETE_INSTALL_VERSION:-latest}"
tmp_dir=""

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

fail() {
  info "$1"
  exit "${2:-1}"
}

cleanup() {
  if [ -n "$tmp_dir" ]; then
    rm -rf "$tmp_dir"
  fi
}
trap cleanup EXIT HUP INT TERM

path_contains() {
  dir="$1"
  case ":${PATH:-}:" in
    *":${dir}:"*) return 0 ;;
    *) return 1 ;;
  esac
}

can_write_dir() {
  dir="$1"
  mkdir -p "$dir" 2>/dev/null || return 1
  [ -d "$dir" ] && [ -w "$dir" ]
}

install_dir() {
  if [ -n "${CONCRETE_INSTALL_BIN_DIR:-}" ]; then
    can_write_dir "$CONCRETE_INSTALL_BIN_DIR" || fail "cannot write CONCRETE_INSTALL_BIN_DIR=${CONCRETE_INSTALL_BIN_DIR}"
    printf '%s\n' "$CONCRETE_INSTALL_BIN_DIR"
    return
  fi

  home_dir="${HOME:-}"
  for dir in "${home_dir}/.local/bin" "${home_dir}/bin" /usr/local/bin /opt/homebrew/bin; do
    if [ -n "$dir" ] && path_contains "$dir" && can_write_dir "$dir"; then
      printf '%s\n' "$dir"
      return
    fi
  done

  if [ -n "$home_dir" ] && can_write_dir "${home_dir}/.local/bin"; then
    info "installing to ${home_dir}/.local/bin; add it to PATH before running concrete"
    printf '%s\n' "${home_dir}/.local/bin"
    return
  fi

  for dir in /usr/local/bin /opt/homebrew/bin; do
    if can_write_dir "$dir"; then
      printf '%s\n' "$dir"
      return
    fi
  done

  fail "could not find a writable install directory; set CONCRETE_INSTALL_BIN_DIR"
}

target_triple() {
  os="$(uname -s 2>/dev/null || true)"
  arch="$(uname -m 2>/dev/null || true)"

  case "$arch" in
    x86_64 | amd64) arch="x86_64" ;;
    arm64 | aarch64) arch="aarch64" ;;
    *) fail "unsupported CPU architecture: ${arch}" ;;
  esac

  case "$os" in
    Linux) printf '%s-unknown-linux-gnu\n' "$arch" ;;
    Darwin) printf '%s-apple-darwin\n' "$arch" ;;
    *) fail "unsupported operating system: ${os}" ;;
  esac
}

download() {
  url="$1"
  output="$2"

  if command -v curl >/dev/null 2>&1; then
    curl -fsSL "$url" -o "$output" && return 0
    return 1
  fi
  if command -v wget >/dev/null 2>&1; then
    wget -q -O "$output" "$url" && return 0
    return 1
  fi
  fail "curl or wget is required"
}

sha256_file() {
  file="$1"

  if command -v sha256sum >/dev/null 2>&1; then
    sha256sum "$file" | awk '{print $1}'
    return
  fi
  if command -v shasum >/dev/null 2>&1; then
    shasum -a 256 "$file" | awk '{print $1}'
    return
  fi
  fail "sha256sum or shasum is required"
}

verify_checksum() {
  file="$1"
  checksum_file="$2"

  expected="$(awk '{print $1; exit}' "$checksum_file")"
  [ -n "$expected" ] || fail "empty checksum file"
  actual="$(sha256_file "$file")"
  [ "$actual" = "$expected" ] || fail "checksum mismatch for downloaded concrete binary"
}

case "$base_url" in
  http://* | https://*) ;;
  *) fail "invalid installer base URL: ${base_url}" ;;
esac

target="$(target_triple)"
tmp_parent="${TMPDIR:-/tmp}"
tmp_dir="$(mktemp -d "${tmp_parent%/}/concrete-install.XXXXXX")"
binary_path="${tmp_dir}/concrete"
checksum_path="${tmp_dir}/concrete.sha256"
artifact_url="${base_url%/}/releases/concrete-cli/${version}/${target}/concrete"
checksum_url="${artifact_url}.sha256"
dest_dir="$(install_dir)"
dest_path="${dest_dir}/concrete"
tmp_dest="${dest_dir}/.concrete.tmp.$$"

info "downloading concrete ${version} for ${target}"
download "$artifact_url" "$binary_path" || fail "no prebuilt concrete binary is available for ${target}"
download "$checksum_url" "$checksum_path" || fail "checksum is not available for ${target}"
verify_checksum "$binary_path" "$checksum_path"

chmod 0755 "$binary_path"
cp "$binary_path" "$tmp_dest"
mv "$tmp_dest" "$dest_path"

if ! path_contains "$dest_dir"; then
  info "${dest_dir} is not on PATH"
fi

info "installed ${dest_path}"
"$dest_path" --version
