#!/bin/sh
set -eu

APP_NAME="Quavil Agent"
BIN_NAME="qvl"
BASE_URL="${QUAVIL_RELEASE_BASE_URL:-https://get.quavil.com}"

is_tty() {
  [ -t 1 ]
}

paint() {
  code="$1"
  shift
  if is_tty; then
    printf '\033[%sm%s\033[0m\n' "$code" "$*"
  else
    printf '%s\n' "$*"
  fi
}

info() {
  paint "1;35" "==> $*"
}

note() {
  paint "0;36" " -> $*"
}

success() {
  paint "1;32" " ok $*"
}

warn() {
  if is_tty; then
    printf '\033[1;33m !! %s\033[0m\n' "$*" >&2
  else
    printf '!! %s\n' "$*" >&2
  fi
}

die() {
  if is_tty; then
    printf '\033[1;31m xx %s\033[0m\n' "$*" >&2
  else
    printf 'xx %s\n' "$*" >&2
  fi
  exit 1
}

have() {
  command -v "$1" >/dev/null 2>&1
}

fetch_text() {
  url="$1"
  if have curl; then
    curl -fsSL "$url"
    return
  fi
  if have wget; then
    wget -qO- "$url"
    return
  fi
  die "curl or wget is required to install ${APP_NAME}"
}

download_file() {
  url="$1"
  destination="$2"
  if have curl; then
    curl -fsSL "$url" -o "$destination"
    return
  fi
  if have wget; then
    wget -qO "$destination" "$url"
    return
  fi
  die "curl or wget is required to install ${APP_NAME}"
}

sha256_file() {
  file="$1"
  if have sha256sum; then
    sha256sum "$file" | awk '{print $1}'
    return
  fi
  if have shasum; then
    shasum -a 256 "$file" | awk '{print $1}'
    return
  fi
  if have openssl; then
    openssl dgst -sha256 "$file" | awk '{print $NF}'
    return
  fi
  die "No SHA-256 tool found (need sha256sum, shasum, or openssl)"
}

detect_platform() {
  os="$(uname -s 2>/dev/null | tr '[:upper:]' '[:lower:]')"
  arch="$(uname -m 2>/dev/null)"

  case "$os" in
    darwin) PLATFORM_OS="darwin" ;;
    linux) PLATFORM_OS="linux" ;;
    *)
      die "Unsupported operating system: ${os}"
      ;;
  esac

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

resolve_install_dir() {
  if [ -n "${QUAVIL_INSTALL_DIR:-}" ]; then
    INSTALL_DIR="$QUAVIL_INSTALL_DIR"
    return
  fi

  if have "$BIN_NAME"; then
    existing_bin="$(command -v "$BIN_NAME" || true)"
    existing_dir="$(dirname "$existing_bin")"
    if [ -n "$existing_dir" ] && [ -w "$existing_dir" ]; then
      INSTALL_DIR="$existing_dir"
      return
    fi
  fi

  if printf '%s' ":${PATH}:" | grep -q ":${HOME}/.local/bin:"; then
    INSTALL_DIR="${HOME}/.local/bin"
    return
  fi

  if [ -d "/usr/local/bin" ] && [ -w "/usr/local/bin" ]; then
    INSTALL_DIR="/usr/local/bin"
    return
  fi

  INSTALL_DIR="${HOME}/.local/bin"
}

print_path_hint() {
  case ":${PATH}:" in
    *":${INSTALL_DIR}:"*) return ;;
  esac

  warn "${INSTALL_DIR} is not on your PATH yet."
  shell_name="$(basename "${SHELL:-sh}")"
  case "$shell_name" in
    zsh)
      printf "   echo 'export PATH=\"%s:\\$PATH\"' >> ~/.zshrc\n" "$INSTALL_DIR"
      ;;
    bash)
      printf "   echo 'export PATH=\"%s:\\$PATH\"' >> ~/.bashrc\n" "$INSTALL_DIR"
      ;;
    fish)
      printf "   fish_add_path %s\n" "$INSTALL_DIR"
      ;;
    *)
      printf "   export PATH=\"%s:\\$PATH\"\n" "$INSTALL_DIR"
      ;;
  esac
}

print_banner() {
  printf '\n'
  printf '%s\n' 'Quavil Agent installer'
  printf '%s\n' '----------------------'
}

print_banner

have uname || die "uname is required"
have tar || die "tar is required"
have mktemp || die "mktemp is required"

detect_platform
resolve_install_dir

VERSION="${QUAVIL_VERSION:-}"
if [ -z "$VERSION" ]; then
  info "Resolving latest release"
  VERSION="$(fetch_text "${BASE_URL}/latest" | tr -d '\r\n')"
fi

[ -n "$VERSION" ] || die "Could not resolve a Quavil release version"

ARCHIVE_URL="${BASE_URL}/download/${PLATFORM_OS}/${PLATFORM_ARCH}?version=${VERSION}"
CHECKSUM_URL="${BASE_URL}/checksum/${PLATFORM_OS}/${PLATFORM_ARCH}?version=${VERSION}"

info "Installing ${APP_NAME} ${VERSION}"
note "platform: ${PLATFORM_OS}/${PLATFORM_ARCH}"
note "target:   ${INSTALL_DIR}/${BIN_NAME}"

TMPDIR_ROOT="${TMPDIR:-/tmp}"
WORKDIR="$(mktemp -d "${TMPDIR_ROOT%/}/quavil-install.XXXXXX")"
ARCHIVE_PATH="${WORKDIR}/quavil.tar.gz"
trap 'rm -rf "$WORKDIR"' EXIT INT TERM HUP

EXPECTED_SHA="$(fetch_text "$CHECKSUM_URL" | tr -d '\r\n')"
[ -n "$EXPECTED_SHA" ] || die "Checksum endpoint returned no data"

info "Downloading release archive"
download_file "$ARCHIVE_URL" "$ARCHIVE_PATH"

ACTUAL_SHA="$(sha256_file "$ARCHIVE_PATH")"
[ "$ACTUAL_SHA" = "$EXPECTED_SHA" ] || die "Checksum mismatch for downloaded archive"
success "Checksum verified"

info "Extracting archive"
tar -xzf "$ARCHIVE_PATH" -C "$WORKDIR"

EXTRACTED_BIN="${WORKDIR}/${BIN_NAME}"
if [ ! -x "$EXTRACTED_BIN" ]; then
  EXTRACTED_BIN="$(find "$WORKDIR" -type f -name "$BIN_NAME" | head -n 1 || true)"
fi
[ -n "$EXTRACTED_BIN" ] && [ -f "$EXTRACTED_BIN" ] || die "Archive did not contain ${BIN_NAME}"

mkdir -p "$INSTALL_DIR"
TARGET_BIN="${INSTALL_DIR}/${BIN_NAME}"

info "Placing binary"
if have install; then
  install -m 0755 "$EXTRACTED_BIN" "$TARGET_BIN"
else
  cp "$EXTRACTED_BIN" "$TARGET_BIN"
  chmod 0755 "$TARGET_BIN"
fi

INSTALLED_VERSION="$("$TARGET_BIN" --version 2>/dev/null || true)"
success "${APP_NAME} is installed"
printf '\n'
printf '   %s\n' "${INSTALLED_VERSION:-${TARGET_BIN}}"
printf '   %s\n' "Run: ${TARGET_BIN} --help"
printf '\n'
print_path_hint
