#!/bin/sh
# Natural CLI installer
#
# Usage:
#   curl -fsSL https://natural.co/install.sh | bash
#
# Environment variables:
#   NATURAL_BASE_URL       Source root for VERSION + artifacts. Default: https://natural.co/install
#   NATURAL_VERSION        Version to install. Default: latest stable from $NATURAL_BASE_URL/VERSION
#   NATURAL_INSTALL_DIR    Directory to install into. Default: $HOME/.natural/bin
#   NATURAL_FORCE          Reinstall even if the requested version is already installed.
#   NATURAL_NO_MODIFY_PATH Do not edit shell profiles to add NATURAL_INSTALL_DIR to PATH.

set -eu

BINARY_NAME="natural"
BASE_URL="${NATURAL_BASE_URL:-https://natural.co/install}"
DEFAULT_INSTALL_DIR="$HOME/.natural/bin"
tmp_dir=""

info() { printf '%s\n' "$@"; }
warn() { printf '%s\n' "$@" >&2; }
error() {
  warn "Error: $*"
  exit 1
}

cleanup() {
  rc=$?
  if [ -n "$tmp_dir" ] && [ -d "$tmp_dir" ]; then
    rm -rf "$tmp_dir"
  fi
  if [ "$rc" -ne 0 ]; then
    warn "Natural CLI installation failed. If this keeps happening, open an issue at https://github.com/naturalpay/cli/issues."
  fi
}
trap cleanup EXIT

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

detect_os() {
  case "$(uname -s)" in
    Darwin) printf '%s\n' "macos" ;;
    Linux) printf '%s\n' "linux" ;;
    *) error "unsupported OS: $(uname -s). This installer supports macOS and Linux." ;;
  esac
}

detect_arch() {
  case "$(uname -m)" in
    x86_64 | amd64) printf '%s\n' "amd64" ;;
    aarch64 | arm64) printf '%s\n' "arm64" ;;
    *) error "unsupported architecture: $(uname -m). This installer supports amd64 and arm64." ;;
  esac
}

checksum_value() {
  checksums_file="$1"
  archive_name="$2"

  awk -v archive="$archive_name" '$2 == archive { print $1; found = 1; exit } END { if (!found) exit 1 }' "$checksums_file"
}

sha256_value() {
  file="$1"

  if command -v shasum >/dev/null 2>&1; then
    shasum -a 256 "$file" | awk '{ print $1 }'
  elif command -v sha256sum >/dev/null 2>&1; then
    sha256sum "$file" | awk '{ print $1 }'
  else
    error "no SHA-256 tool found. Install shasum or sha256sum and retry."
  fi
}

verify_checksum() {
  archive_path="$1"
  checksums_path="$2"
  archive_name="$(basename "$archive_path")"

  expected="$(checksum_value "$checksums_path" "$archive_name")" ||
    error "checksum not found for $archive_name"
  actual="$(sha256_value "$archive_path")"

  [ "$expected" = "$actual" ] ||
    error "checksum mismatch for $archive_name"
}

installed_version() {
  command -v "$BINARY_NAME" >/dev/null 2>&1 || return 1
  "$BINARY_NAME" --version 2>/dev/null | awk 'NR == 1 { print $NF }'
}

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

append_path_block() {
  profile="$1"
  line="$2"

  mkdir -p "$(dirname "$profile")"
  touch "$profile"

  if grep -F '# >>> natural >>>' "$profile" >/dev/null 2>&1; then
    return 1
  fi

  {
    printf '\n# >>> natural >>>\n'
    printf '%s\n' "$line"
    printf '# <<< natural <<<\n'
  } >>"$profile"
  return 0
}

add_to_path() {
  install_dir="$1"

  if [ "${NATURAL_NO_MODIFY_PATH:-}" = "1" ]; then
    warn "Add Natural to your PATH manually: export PATH=\"$install_dir:\$PATH\""
    return
  fi

  if path_contains "$install_dir"; then
    return
  fi

  shell_name="$(basename "${SHELL:-}")"
  uname_s="$(uname -s)"
  modified_profiles=""

  case "$shell_name" in
    zsh)
      if [ "$uname_s" = "Darwin" ]; then
        for profile in "$HOME/.zprofile" "$HOME/.zshrc"; do
          if append_path_block "$profile" "export PATH=\"$install_dir:\$PATH\""; then
            modified_profiles="${modified_profiles}${modified_profiles:+ }$profile"
          fi
        done
      else
        if append_path_block "$HOME/.zshrc" "export PATH=\"$install_dir:\$PATH\""; then
          modified_profiles="$HOME/.zshrc"
        fi
      fi
      ;;
    bash)
      if [ "$uname_s" = "Darwin" ]; then
        if append_path_block "$HOME/.bash_profile" "export PATH=\"$install_dir:\$PATH\""; then
          modified_profiles="$HOME/.bash_profile"
        fi
      else
        if append_path_block "$HOME/.bashrc" "export PATH=\"$install_dir:\$PATH\""; then
          modified_profiles="$HOME/.bashrc"
        fi
      fi
      ;;
    fish)
      fish_config="$HOME/.config/fish/config.fish"
      if append_path_block "$fish_config" "fish_add_path \"$install_dir\""; then
        modified_profiles="$fish_config"
      fi
      ;;
    *)
      warn "Add Natural to your PATH manually: export PATH=\"$install_dir:\$PATH\""
      return
      ;;
  esac

  if [ -n "$modified_profiles" ]; then
    info "Added $install_dir to PATH in: $modified_profiles"
    info "Restart your shell or source the profile file before running natural."
  else
    warn "Add Natural to your PATH manually: export PATH=\"$install_dir:\$PATH\""
  fi
}

main() {
  need_cmd curl
  need_cmd uname
  need_cmd mktemp
  need_cmd awk
  need_cmd basename
  need_cmd dirname
  need_cmd grep
  need_cmd tr

  os="$(detect_os)"
  arch="$(detect_arch)"

  case "$os" in
    macos)
      ext="zip"
      need_cmd unzip
      ;;
    linux)
      ext="tar.gz"
      need_cmd tar
      ;;
    *)
      error "unsupported OS: $os"
      ;;
  esac

  if [ -n "${NATURAL_VERSION:-}" ]; then
    version="$NATURAL_VERSION"
  else
    info "Fetching latest Natural CLI version..."
    version="$(curl -fsSL "$BASE_URL/VERSION" | tr -d '[:space:]')"
  fi
  [ -n "$version" ] || error "could not determine Natural CLI version"

  if [ "${NATURAL_FORCE:-}" != "1" ]; then
    current="$(installed_version || true)"
    if [ "$current" = "$version" ]; then
      info "Natural CLI v$version is already installed."
      exit 0
    fi
  fi

  archive="natural_${version}_${os}_${arch}.${ext}"
  checksums="natural_${version}_checksums.txt"
  install_dir="${NATURAL_INSTALL_DIR:-$DEFAULT_INSTALL_DIR}"

  tmp_dir="$(mktemp -d)"
  extract_dir="$tmp_dir/extract"
  mkdir -p "$extract_dir"

  info "Installing Natural CLI v$version ($os/$arch)..."
  info "Downloading $archive..."
  curl -fsSL "$BASE_URL/v${version}/${archive}" -o "$tmp_dir/$archive"
  curl -fsSL "$BASE_URL/v${version}/${checksums}" -o "$tmp_dir/$checksums"

  info "Verifying checksum..."
  verify_checksum "$tmp_dir/$archive" "$tmp_dir/$checksums"

  case "$archive" in
    *.zip) unzip -oq "$tmp_dir/$archive" -d "$extract_dir" ;;
    *.tar.gz) tar -xzf "$tmp_dir/$archive" -C "$extract_dir" ;;
    *) error "unknown archive format: $archive" ;;
  esac

  binary_path="$extract_dir/$BINARY_NAME"
  [ -f "$binary_path" ] || error "archive did not contain $BINARY_NAME binary"

  mkdir -p "$install_dir"
  cp "$binary_path" "$install_dir/$BINARY_NAME.tmp.$$"
  chmod +x "$install_dir/$BINARY_NAME.tmp.$$"
  mv "$install_dir/$BINARY_NAME.tmp.$$" "$install_dir/$BINARY_NAME"

  add_to_path "$install_dir"

  info ""
  info "Natural CLI v$version installed to $install_dir/$BINARY_NAME"
  if command -v "$BINARY_NAME" >/dev/null 2>&1; then
    info "Run 'natural --help' to get started."
  else
    info "Run this now, or restart your shell: export PATH=\"$install_dir:\$PATH\""
  fi
}

main "$@"
