#!/usr/bin/env bash
# install-dep.sh — Install a single dependency for Android reverse engineering
# Usage: install-dep.sh <dependency>
# Dependencies: java, jadx, vineflower, dex2jar, apktool, adb
#
# Exit codes:
#   0 — installed successfully
#   1 — installation failed
#   2 — requires manual action (e.g. sudo needed but not available)
set -euo pipefail

usage() {
  cat <<EOF
Usage: install-dep.sh <dependency>

Install a dependency required for Android reverse engineering.

Available dependencies:
  java         Java JDK 17+
  jadx         jadx decompiler
  vineflower   Vineflower (Fernflower fork) decompiler
  dex2jar      DEX to JAR converter
  apktool      Android resource decoder
  adb          Android Debug Bridge

The script detects your OS and package manager, then:
  - Installs directly if possible (brew, or user-local install)
  - Uses sudo if available and needed
  - Prints manual instructions if neither option works
EOF
  exit 0
}

if [[ $# -lt 1 || "$1" == "-h" || "$1" == "--help" ]]; then
  usage
fi

DEP="$1"

# --- Detect environment ---
OS="unknown"
PKG_MANAGER="none"
HAS_SUDO=false
ARCH=$(uname -m)

case "$(uname -s)" in
  Linux)  OS="linux" ;;
  Darwin) OS="macos" ;;
esac

# Detect package manager
if command -v brew &>/dev/null; then
  PKG_MANAGER="brew"
elif command -v apt-get &>/dev/null; then
  PKG_MANAGER="apt"
elif command -v dnf &>/dev/null; then
  PKG_MANAGER="dnf"
elif command -v pacman &>/dev/null; then
  PKG_MANAGER="pacman"
fi

# Check sudo availability
if command -v sudo &>/dev/null; then
  if sudo -n true 2>/dev/null; then
    HAS_SUDO=true
  else
    # sudo exists but may need password — we'll try it and let it prompt
    HAS_SUDO=true
  fi
fi

info()  { echo "[INFO] $*"; }
ok()    { echo "[OK] $*"; }
fail()  { echo "[FAIL] $*" >&2; }
manual() {
  echo "[MANUAL] $*" >&2
  echo "         Cannot install automatically. Please install manually and retry." >&2
  exit 2
}

# --- Helper: install via system package manager (needs sudo on Linux) ---
pkg_install() {
  local pkg="$1"
  case "$PKG_MANAGER" in
    brew)
      info "Installing $pkg via Homebrew..."
      brew install "$pkg"
      ;;
    apt)
      if [[ "$HAS_SUDO" == true ]]; then
        info "Installing $pkg via apt..."
        sudo apt-get update -qq && sudo apt-get install -y -qq "$pkg"
      else
        manual "Run: sudo apt-get install $pkg"
      fi
      ;;
    dnf)
      if [[ "$HAS_SUDO" == true ]]; then
        info "Installing $pkg via dnf..."
        sudo dnf install -y "$pkg"
      else
        manual "Run: sudo dnf install $pkg"
      fi
      ;;
    pacman)
      if [[ "$HAS_SUDO" == true ]]; then
        info "Installing $pkg via pacman..."
        sudo pacman -S --noconfirm "$pkg"
      else
        manual "Run: sudo pacman -S $pkg"
      fi
      ;;
    *)
      manual "No supported package manager found. Install $pkg manually."
      ;;
  esac
}

# --- Helper: download a file ---
download() {
  local url="$1" dest="$2"
  if command -v curl &>/dev/null; then
    curl -fsSL -o "$dest" "$url"
  elif command -v wget &>/dev/null; then
    wget -q -O "$dest" "$url"
  else
    fail "Neither curl nor wget available."
    return 1
  fi
}

# --- Helper: get latest GitHub release tag ---
gh_latest_tag() {
  local repo="$1"
  local url="https://api.github.com/repos/$repo/releases/latest"
  if command -v curl &>/dev/null; then
    curl -fsSL "$url" | grep '"tag_name"' | head -1 | sed 's/.*"tag_name":[[:space:]]*"\([^"]*\)".*/\1/'
  elif command -v wget &>/dev/null; then
    wget -q -O - "$url" | grep '"tag_name"' | head -1 | sed 's/.*"tag_name":[[:space:]]*"\([^"]*\)".*/\1/'
  fi
}

# --- Helper: add a line to shell profile if not already present ---
add_to_profile() {
  local line="$1"
  local profile=""
  if [[ -f "$HOME/.zshrc" ]]; then
    profile="$HOME/.zshrc"
  elif [[ -f "$HOME/.bashrc" ]]; then
    profile="$HOME/.bashrc"
  elif [[ -f "$HOME/.profile" ]]; then
    profile="$HOME/.profile"
  fi

  if [[ -n "$profile" ]]; then
    if ! grep -qF "$line" "$profile" 2>/dev/null; then
      echo "$line" >> "$profile"
      info "Added to $profile: $line"
      info "Run 'source $profile' or start a new shell to apply."
    fi
  else
    info "Add this to your shell profile: $line"
  fi
}

# =====================================================================
# Dependency installers
# =====================================================================

install_java() {
  if command -v java &>/dev/null; then
    local ver
    ver=$(java -version 2>&1 | head -1 | sed -n 's/.*"\([0-9]*\)\..*/\1/p')
    if [[ -n "$ver" ]] && (( ver >= 17 )); then
      ok "Java $ver already installed"
      return 0
    fi
  fi

  info "Installing Java JDK 17+..."
  case "$PKG_MANAGER" in
    brew)    brew install openjdk@17 ;;
    apt)     pkg_install "openjdk-17-jdk" ;;
    dnf)     pkg_install "java-17-openjdk-devel" ;;
    pacman)  pkg_install "jdk17-openjdk" ;;
    *)       manual "Install Java JDK 17+ from https://adoptium.net/" ;;
  esac

  # Verify
  if command -v java &>/dev/null; then
    ok "Java installed: $(java -version 2>&1 | head -1)"
  else
    fail "Java installation may require PATH update."
    if [[ "$PKG_MANAGER" == "brew" ]]; then
      add_to_profile 'export PATH="/opt/homebrew/opt/openjdk@17/bin:$PATH"'
    fi
    exit 1
  fi
}

install_jadx() {
  if command -v jadx &>/dev/null; then
    ok "jadx already installed: $(jadx --version 2>/dev/null || echo 'unknown')"
    return 0
  fi

  # Try brew first (cleanest)
  if [[ "$PKG_MANAGER" == "brew" ]]; then
    info "Installing jadx via Homebrew..."
    brew install jadx
    ok "jadx installed via Homebrew"
    return 0
  fi

  # User-local install from GitHub releases (no sudo needed)
  info "Installing jadx from GitHub releases..."
  local tag
  tag=$(gh_latest_tag "skylot/jadx")
  if [[ -z "$tag" ]]; then
    fail "Could not determine latest jadx version."
    manual "Download from https://github.com/skylot/jadx/releases/latest"
  fi

  local version="${tag#v}"
  local url="https://github.com/skylot/jadx/releases/download/${tag}/jadx-${version}.zip"
  local tmp_zip
  tmp_zip=$(mktemp /tmp/jadx-XXXXXX.zip)

  info "Downloading jadx $version..."
  download "$url" "$tmp_zip"

  local install_dir="$HOME/.local/share/jadx"
  rm -rf "$install_dir"
  mkdir -p "$install_dir"
  unzip -qo "$tmp_zip" -d "$install_dir"
  rm -f "$tmp_zip"
  chmod +x "$install_dir/bin/jadx" "$install_dir/bin/jadx-gui" 2>/dev/null || true

  # Add to PATH
  mkdir -p "$HOME/.local/bin"
  ln -sf "$install_dir/bin/jadx" "$HOME/.local/bin/jadx"
  ln -sf "$install_dir/bin/jadx-gui" "$HOME/.local/bin/jadx-gui"
  export PATH="$HOME/.local/bin:$PATH"
  add_to_profile 'export PATH="$HOME/.local/bin:$PATH"'

  if command -v jadx &>/dev/null; then
    ok "jadx $version installed to $install_dir"
  else
    ok "jadx $version installed to $install_dir"
    info "Run: export PATH=\"\$HOME/.local/bin:\$PATH\" to use it now"
  fi
}

install_vineflower() {
  # Check if already available
  if command -v vineflower &>/dev/null || command -v fernflower &>/dev/null; then
    ok "Vineflower/Fernflower CLI already installed"
    return 0
  fi
  for candidate in \
    "${FERNFLOWER_JAR_PATH:-}" \
    "$HOME/vineflower/vineflower.jar" \
    "$HOME/fernflower/fernflower.jar" \
    "$HOME/fernflower/build/libs/fernflower.jar" \
    "$HOME/vineflower/build/libs/vineflower.jar"; do
    if [[ -n "$candidate" ]] && [[ -f "$candidate" ]]; then
      ok "Vineflower/Fernflower JAR already exists: $candidate"
      return 0
    fi
  done

  # Try brew
  if [[ "$PKG_MANAGER" == "brew" ]]; then
    info "Installing vineflower via Homebrew..."
    if brew install vineflower 2>/dev/null; then
      ok "Vineflower installed via Homebrew"
      return 0
    fi
    info "Homebrew formula not available, falling back to direct download."
  fi

  # Download JAR from GitHub releases (no sudo needed)
  info "Installing Vineflower from GitHub releases..."
  local tag
  tag=$(gh_latest_tag "Vineflower/vineflower")
  if [[ -z "$tag" ]]; then
    fail "Could not determine latest Vineflower version."
    manual "Download from https://github.com/Vineflower/vineflower/releases/latest"
  fi

  local version="${tag#v}"
  local url="https://github.com/Vineflower/vineflower/releases/download/${tag}/vineflower-${version}.jar"
  local install_dir="$HOME/.local/share/vineflower"
  mkdir -p "$install_dir"

  info "Downloading Vineflower $version..."
  download "$url" "$install_dir/vineflower.jar"

  # Create wrapper script
  mkdir -p "$HOME/.local/bin"
  cat > "$HOME/.local/bin/vineflower" <<'WRAPPER'
#!/usr/bin/env bash
exec java -jar "$HOME/.local/share/vineflower/vineflower.jar" "$@"
WRAPPER
  chmod +x "$HOME/.local/bin/vineflower"

  export PATH="$HOME/.local/bin:$PATH"
  export FERNFLOWER_JAR_PATH="$install_dir/vineflower.jar"
  add_to_profile 'export PATH="$HOME/.local/bin:$PATH"'
  add_to_profile "export FERNFLOWER_JAR_PATH=\"$install_dir/vineflower.jar\""

  ok "Vineflower $version installed to $install_dir/vineflower.jar"
  info "FERNFLOWER_JAR_PATH set to $install_dir/vineflower.jar"
}

install_dex2jar() {
  if command -v d2j-dex2jar &>/dev/null || command -v d2j-dex2jar.sh &>/dev/null; then
    ok "dex2jar already installed"
    return 0
  fi

  # Try brew
  if [[ "$PKG_MANAGER" == "brew" ]]; then
    info "Installing dex2jar via Homebrew..."
    if brew install dex2jar 2>/dev/null; then
      ok "dex2jar installed via Homebrew"
      return 0
    fi
    info "Homebrew formula not available, falling back to direct download."
  fi

  # Download from GitHub (no sudo needed)
  info "Installing dex2jar from GitHub releases..."
  local tag
  tag=$(gh_latest_tag "ThexXTURBOXx/dex2jar")
  if [[ -z "$tag" ]]; then
    # Fallback to a known maintained release if GitHub metadata is unavailable.
    tag="2.4.35"
  fi

  local version="${tag#v}"
  local url="https://github.com/ThexXTURBOXx/dex2jar/releases/download/${tag}/dex-tools-${version}.zip"
  local tmp_zip
  tmp_zip=$(mktemp /tmp/dex2jar-XXXXXX.zip)

  info "Downloading dex2jar $version..."
  if ! download "$url" "$tmp_zip"; then
    # Try alternate naming
    url="https://github.com/ThexXTURBOXx/dex2jar/releases/download/${tag}/dex-tools-v${version}.zip"
    download "$url" "$tmp_zip" || {
      fail "Download failed."
      manual "Download from https://github.com/ThexXTURBOXx/dex2jar/releases/latest"
    }
  fi

  local install_dir="$HOME/.local/share/dex2jar"
  rm -rf "$install_dir"
  mkdir -p "$install_dir"
  unzip -qo "$tmp_zip" -d "$install_dir"
  rm -f "$tmp_zip"

  # The zip may contain a top-level directory — find the actual bin location
  local bin_dir=""
  if [[ -f "$install_dir/d2j-dex2jar.sh" ]]; then
    bin_dir="$install_dir"
  else
    bin_dir=$(find "$install_dir" -name "d2j-dex2jar.sh" -exec dirname {} \; | head -1)
  fi

  if [[ -z "$bin_dir" ]]; then
    fail "Could not find d2j-dex2jar.sh in extracted archive."
    manual "Download and extract manually from https://github.com/ThexXTURBOXx/dex2jar/releases"
  fi

  chmod +x "$bin_dir"/*.sh 2>/dev/null || true

  mkdir -p "$HOME/.local/bin"
  for script in "$bin_dir"/d2j-*.sh; do
    local name
    name=$(basename "$script" .sh)
    ln -sf "$script" "$HOME/.local/bin/$name"
  done

  export PATH="$HOME/.local/bin:$PATH"
  add_to_profile 'export PATH="$HOME/.local/bin:$PATH"'

  ok "dex2jar $version installed to $install_dir"
}

install_apktool() {
  if command -v apktool &>/dev/null; then
    ok "apktool already installed"
    return 0
  fi

  case "$PKG_MANAGER" in
    brew)    info "Installing apktool via Homebrew..."; brew install apktool ;;
    apt)     pkg_install "apktool" ;;
    *)       manual "Install apktool from https://apktool.org/docs/install" ;;
  esac

  if command -v apktool &>/dev/null; then
    ok "apktool installed"
  else
    fail "apktool installation may have failed."
    exit 1
  fi
}

install_adb() {
  if command -v adb &>/dev/null; then
    ok "adb already installed"
    return 0
  fi

  case "$PKG_MANAGER" in
    brew)    info "Installing adb via Homebrew..."; brew install android-platform-tools ;;
    apt)     pkg_install "adb" ;;
    dnf)     pkg_install "android-tools" ;;
    pacman)  pkg_install "android-tools" ;;
    *)       manual "Install Android SDK Platform Tools from https://developer.android.com/tools/releases/platform-tools" ;;
  esac

  if command -v adb &>/dev/null; then
    ok "adb installed"
  else
    fail "adb installation may have failed."
    exit 1
  fi
}

# =====================================================================
# Dispatch
# =====================================================================

case "$DEP" in
  java)        install_java ;;
  jadx)        install_jadx ;;
  vineflower|fernflower)  install_vineflower ;;
  dex2jar)     install_dex2jar ;;
  apktool)     install_apktool ;;
  adb)         install_adb ;;
  *)
    echo "Error: Unknown dependency '$DEP'" >&2
    echo "Available: java, jadx, vineflower, dex2jar, apktool, adb" >&2
    exit 1
    ;;
esac
