#!/bin/sh

set -eu

OWNER="${LOOPER_GITHUB_OWNER:-nexu-io}"
REPO="${LOOPER_GITHUB_REPO:-looper}"
VERSION="${LOOPER_VERSION:-latest}"

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

fail() {
  printf 'error: %s\n' "$*" >&2
  exit 1
}

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

detect_target() {
  os="$(uname -s)"
  arch="$(uname -m)"

  case "$os" in
    Darwin)
      case "$arch" in
        arm64|aarch64) printf 'darwin-arm64\n' ;;
        *) fail "unsupported architecture for macOS: $arch (supported: arm64)" ;;
      esac
      ;;
    Linux)
      case "$arch" in
        x86_64|amd64) printf 'linux-amd64\n' ;;
        *) fail "unsupported architecture for Linux: $arch (supported: x86_64)" ;;
      esac
      ;;
    *) fail "unsupported platform: $os (supported: macOS, Linux)" ;;
  esac
}

in_path_dir() {
  candidate="$1"
  old_ifs=$IFS
  IFS=:
  for entry in $PATH; do
    [ "$entry" = "$candidate" ] && IFS=$old_ifs && return 0
  done
  IFS=$old_ifs
  return 1
}

guess_profile() {
  shell_name="${SHELL:-}"
  shell_name="${shell_name##*/}"
  case "$shell_name" in
    zsh) printf '%s/.zprofile\n' "$HOME" ;;
    bash) printf '%s/.bash_profile\n' "$HOME" ;;
    *) printf '%s/.profile\n' "$HOME" ;;
  esac
}

confirm() {
  prompt="$1"
  if [ ! -t 0 ]; then
    return 1
  fi
  printf '%s [y/N] ' "$prompt" >&2
  read -r answer || return 1
  case "$answer" in
    y|Y|yes|YES) return 0 ;;
    *) return 1 ;;
  esac
}

append_path_export() {
  profile="$1"
  install_dir="$2"
  if [ "$install_dir" = "$HOME/.local/bin" ]; then
    export_line='export PATH="$HOME/.local/bin:$PATH"'
  else
    export_line="export PATH=\"$install_dir:\$PATH\""
  fi
  mkdir -p "$(dirname "$profile")"
  touch "$profile"
  if grep -F "$export_line" "$profile" >/dev/null 2>&1; then
    return 0
  fi
  {
    printf '\n# Added by looper installer\n'
    printf '%s\n' "$export_line"
  } >>"$profile"
}

pick_install_dir() {
  if [ -n "${LOOPER_INSTALL_DIR:-}" ]; then
    printf '%s\n' "$LOOPER_INSTALL_DIR"
    return 0
  fi

  printf '%s/.local/bin\n' "$HOME"
}

build_download_base() {
  tag="$1"
  if [ "$tag" = "latest" ]; then
    printf 'https://github.com/%s/%s/releases/latest/download\n' "$OWNER" "$REPO"
  else
    printf 'https://github.com/%s/%s/releases/download/%s\n' "$OWNER" "$REPO" "$tag"
  fi
}

verify_checksum() {
  file="$1"
  expected="$2"
  if command -v shasum >/dev/null 2>&1; then
    actual="$(shasum -a 256 "$file" | awk '{print $1}')"
  elif command -v sha256sum >/dev/null 2>&1; then
    actual="$(sha256sum "$file" | awk '{print $1}')"
  elif command -v openssl >/dev/null 2>&1; then
    actual="$(openssl dgst -sha256 "$file" | awk '{print $NF}')"
  else
    fail "missing checksum tool (need shasum, sha256sum, or openssl)"
  fi

  [ "$actual" = "$expected" ] || fail "checksum mismatch: expected $expected, got $actual"
}

curl_supports_progress_bar() {
  curl --help all 2>/dev/null | grep -q -- '--progress-bar'
}

show_download_progress() {
  case "${LOOPER_DOWNLOAD_PROGRESS:-auto}" in
    0|false|False|FALSE|no|No|NO|never|Never|NEVER)
      return 1
      ;;
    1|true|True|TRUE|yes|Yes|YES|always|Always|ALWAYS)
      curl_supports_progress_bar
      return
      ;;
  esac

  [ -t 2 ] && curl_supports_progress_bar
}

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

  if show_download_progress; then
    curl -fL --progress-bar "$url" -o "$output"
  else
    curl -fsSL "$url" -o "$output"
  fi
}

need_cmd curl
need_cmd grep
need_cmd tar

target="$(detect_target)"
asset="looper-$target"
archive_asset="$asset.tar.gz"
download_base="$(build_download_base "$VERSION")"
binary_url="$download_base/$asset"
checksum_url="$download_base/$asset.sha256"
archive_url="$download_base/$archive_asset"
archive_checksum_url="$download_base/$archive_asset.sha256"

install_dir="$(pick_install_dir)"
mkdir -p "$install_dir"

profile_updated=0
if ! in_path_dir "$install_dir"; then
  if [ "$install_dir" = "$HOME/.local/bin" ]; then
    profile="$(guess_profile)"
    if confirm "~/.local/bin is not on PATH. Add it to $(basename "$profile")?"; then
      append_path_export "$profile" "$install_dir"
      profile_updated=1
    fi
  fi
fi

tmp_dir="$(mktemp -d)"
trap 'rm -rf "$tmp_dir"' EXIT INT TERM HUP

tmp_binary="$tmp_dir/looper"

# Prefer the gzipped tarball when the release publishes one. It is roughly a
# third of the size of the raw binary on macOS arm64, so first install and
# self-upgrade both transfer dramatically less data. The script falls back to
# the raw binary asset only when the archive returns 404, which keeps users
# on pinned older releases unaffected.
http_status_for() {
  curl -fsSLI -o /dev/null -w '%{http_code}' "$1" 2>/dev/null || true
}

archive_status="$(http_status_for "$archive_url")"
archive_checksum_status="$(http_status_for "$archive_checksum_url")"
if { [ "$archive_status" = "200" ] || [ "$archive_status" = "302" ]; } &&
   { [ "$archive_checksum_status" = "200" ] || [ "$archive_checksum_status" = "302" ]; }; then
  archive_path="$tmp_dir/$archive_asset"
  archive_checksum_path="$tmp_dir/$archive_asset.sha256"

  log "Downloading $archive_url"
  download_file "$archive_url" "$archive_path"
  download_file "$archive_checksum_url" "$archive_checksum_path"

  expected_checksum="$(awk '{print $1}' "$archive_checksum_path")"
  [ -n "$expected_checksum" ] || fail "invalid checksum file: $archive_checksum_url"
  verify_checksum "$archive_path" "$expected_checksum"

  tar -xzf "$archive_path" -C "$tmp_dir"
  [ -f "$tmp_dir/$asset" ] || fail "archive $archive_asset did not contain $asset"
  mv "$tmp_dir/$asset" "$tmp_binary"
else
  log "Archive or checksum unavailable (archive HTTP ${archive_status:-?}, checksum HTTP ${archive_checksum_status:-?}); using raw binary."
  tmp_checksum="$tmp_dir/$asset.sha256"

  log "Downloading $binary_url"
  download_file "$binary_url" "$tmp_binary"
  download_file "$checksum_url" "$tmp_checksum"

  expected_checksum="$(awk '{print $1}' "$tmp_checksum")"
  [ -n "$expected_checksum" ] || fail "invalid checksum file: $checksum_url"

  verify_checksum "$tmp_binary" "$expected_checksum"
fi

chmod 0755 "$tmp_binary"
install_path="$install_dir/looper"
mv "$tmp_binary" "$install_path"

log "Installed looper to $install_path"
if [ "$profile_updated" -eq 1 ]; then
  log "Added $install_dir to PATH in $(guess_profile)"
fi

if ! in_path_dir "$install_dir"; then
  log "Open a new shell or run: export PATH=\"$install_dir:\$PATH\""
fi

log ""
log "This installer only installs the looper CLI."
log "looper bootstrap will install/start the matching looperd daemon."
log ""
log "Next steps:"
log "  looper bootstrap"
log "  looper status"
log ""
log "Manual daemon fallback/debug commands:"
log "  looper daemon install"
log "  looper daemon start"
