#!/usr/bin/env bash
# Also supports the documented `curl ... | sh` entry point (Debian dash).
set -eu

BASE_URL="${INLINE_RELEASE_BASE_URL:-https://public-assets.inline.chat/cli}"
MANIFEST_URL="${INLINE_RELEASE_MANIFEST_URL:-${BASE_URL%/}/manifest.json}"

RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'

log() { printf '%b%s%b %s\n' "$BLUE" '[INFO]' "$NC" "$1" >&2; }
warn() { printf '%b%s%b %s\n' "$YELLOW" '[WARN]' "$NC" "$1" >&2; }
error() { printf '%b%s%b %s\n' "$RED" '[ERROR]' "$NC" "$1" >&2; exit 1; }
success() { printf '%b%s%b %s\n' "$GREEN" '[OK]' "$NC" "$1" >&2; }

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

cleanup() {
  if [ -n "${TMPDIR_CLEANUP:-}" ] && [ -d "$TMPDIR_CLEANUP" ]; then
    rm -rf "$TMPDIR_CLEANUP"
  fi
}

trap cleanup EXIT INT TERM

need_cmd() {
  if ! command_exists "$1"; then
    error "need '$1' (command not found)"
  fi
}

check_prereqs() {
  need_cmd uname
  need_cmd mktemp
  need_cmd tar
  need_cmd install
  if command_exists shasum; then
    SHA256_CMD="shasum -a 256"
  elif command_exists sha256sum; then
    SHA256_CMD="sha256sum"
  else
    error "need 'shasum' or 'sha256sum' (command not found)"
  fi
  if ! command_exists curl && ! command_exists wget; then
    error "need 'curl' or 'wget' (command not found)"
  fi
}

downloader() {
  local url="$1"
  local output_file="$2"

  if command_exists curl; then
    curl -fsSL "$url" -o "$output_file"
  elif command_exists wget; then
    wget -q -O "$output_file" "$url"
  else
    error "Neither curl nor wget found"
  fi
}

download_file() {
  local url="$1"
  local output_file="$2"
  local temp_file
  temp_file=$(mktemp "$(dirname "$output_file")/tmp.XXXXXX")
  downloader "$url" "$temp_file"
  mv "$temp_file" "$output_file"
}

can_write_dir() {
  local dir="$1"
  if [ -d "$dir" ]; then
    [ -w "$dir" ]
    return
  fi

  local parent
  parent="$(dirname "$dir")"
  while [ ! -d "$parent" ]; do
    parent="$(dirname "$parent")"
  done
  [ -w "$parent" ]
}

install_user_writable() {
  local dir="$1"
  if ! can_write_dir "$dir"; then
    return 1
  fi

  mkdir -p "$dir"
  install -m 0755 "$TMPDIR_CLEANUP/inline" "$dir/inline"
}

install_with_sudo() {
  local dir="$1"
  if ! command_exists sudo; then
    return 1
  fi

  sudo install -d -m 0755 "$dir"
  sudo install -m 0755 "$TMPDIR_CLEANUP/inline" "$dir/inline"
}

existing_inline_dir() {
  local existing_path
  existing_path="$(command -v inline 2>/dev/null || true)"
  case "$existing_path" in
    /*/inline)
      if [ -f "$existing_path" ] && [ ! -L "$existing_path" ]; then
        dirname "$existing_path"
        return 0
      fi
      ;;
  esac
  return 1
}

install_binary() {
  local requested_dir="${INLINE_INSTALL_DIR:-}"
  local install_dir

  if [ -n "$requested_dir" ]; then
    install_dir="$requested_dir"
    if install_user_writable "$install_dir" || install_with_sudo "$install_dir"; then
      echo "$install_dir/inline"
      return 0
    fi
    error "Failed to install into $install_dir"
  fi

  if install_dir="$(existing_inline_dir)"; then
    if install_user_writable "$install_dir" || install_with_sudo "$install_dir"; then
      echo "$install_dir/inline"
      return 0
    fi
    warn "Could not update the existing inline binary in $install_dir; trying a standard install location."
  fi

  install_dir="/usr/local/bin"
  if install_user_writable "$install_dir" || install_with_sudo "$install_dir"; then
    echo "$install_dir/inline"
    return 0
  fi

  if [ -z "${HOME:-}" ]; then
    error "HOME is not set and inline could not be installed into $install_dir"
  fi

  install_dir="$HOME/.local/bin"
  if install_user_writable "$install_dir"; then
    echo "$install_dir/inline"
    return 0
  fi

  error "Failed to install into $install_dir"
}

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

  case "$os" in
    Darwin)
      case "$arch" in
        arm64) echo "aarch64-apple-darwin" ;;
        x86_64) error "Intel macOS is no longer supported; Inline CLI requires Apple silicon" ;;
        *) error "Unsupported architecture: $arch" ;;
      esac
      ;;
    Linux)
      libc="gnu"
      if command_exists ldd && ldd --version 2>&1 | grep -qi musl; then
        libc="musl"
      fi
      case "$arch" in
        aarch64|arm64) echo "aarch64-unknown-linux-${libc}" ;;
        x86_64|amd64) echo "x86_64-unknown-linux-${libc}" ;;
        *) error "Unsupported architecture: $arch" ;;
      esac
      ;;
    *)
      error "Unsupported OS: $os"
      ;;
  esac
}

check_prereqs

TMPDIR_CLEANUP="$(mktemp -d)"

log "Fetching manifest..."
manifest_file="$TMPDIR_CLEANUP/manifest.json"
download_file "$MANIFEST_URL" "$manifest_file"
manifest="$(cat "$manifest_file")"

target="$(detect_target)"
log "Detected target: $target"

if command_exists jq; then
  version="$(printf '%s' "$manifest" | jq -r '.version // empty')"
  url="$(printf '%s' "$manifest" | jq -r --arg t "$target" '.targets[$t].url // empty')"
  sha256="$(printf '%s' "$manifest" | jq -r --arg t "$target" '.targets[$t].sha256 // empty')"
else
  compact="$(printf '%s' "$manifest" | tr -d '\n\r\t')"
  version="$(printf '%s' "$compact" | sed -n 's/.*"version"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | head -n1)"
  target_block="$(printf '%s' "$compact" | sed -n "s/.*\"$target\"[[:space:]]*:[[:space:]]*{\\([^}]*\\)}.*/\\1/p" | head -n1)"
  url="$(printf '%s' "$target_block" | sed -n 's/.*"url"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | head -n1)"
  sha256="$(printf '%s' "$target_block" | sed -n 's/.*"sha256"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | head -n1)"
fi

if [ -z "$version" ] || [ -z "$url" ] || [ -z "$sha256" ]; then
  error "No release found for $target"
fi

archive="$TMPDIR_CLEANUP/inline.tar.gz"

log "Downloading inline v$version..."
download_file "$url" "$archive"

log "Verifying checksum..."
echo "$sha256  $archive" | $SHA256_CMD -c -

tar -xzf "$archive" -C "$TMPDIR_CLEANUP"

if [ ! -f "$TMPDIR_CLEANUP/inline" ]; then
  error "Archive did not contain inline binary"
fi

install_path="$(install_binary)"
install_dir="$(dirname "$install_path")"

success "Installed inline v$version to $install_path"
if ! echo "$PATH" | tr ':' '\n' | grep -qx "$install_dir"; then
  warn "$install_dir is not on your PATH. Add it to run 'inline'."
fi
