#!/data/data/com.itsaky.androidide/files/usr/bin/bash

# Modified by Mohammed-baqer-null @ https://github.com/Mohammed-baqer-null
# ++ ndk support 

Color_Off='\033[0m'
Red='\033[0;31m'
Green='\033[0;32m'
Blue='\033[0;34m'
Orange="\e[38;5;208m"

yes='^[Yy][Ee]?[Ss]?$'

# Defualt values
arch=$(uname -m)
install_dir=$HOME
sdkver_org=34.0.4
with_cmdline=true
assume_yes=false
manifest="https://raw.githubusercontent.com/AndroidIDEOfficial/androidide-tools/main/manifest.json"
pkgm="pkg"
pkg_curl="libcurl"
pkgs="jq tar"
jdk_version="17"
ndk=false

npr() {
    local TAG="$Green[ NDK SETUP ]$Color_Off"
    echo -e "$TAG $1"
}

ensure_ndk() {
    local ndkVersion="27.1.12297006"
    if [ -f "$HOME/android-sdk/ndk/$ndkVersion/ndk-build" ]; then
        return 0
    fi
    return 1
}

download_and_extract_ndk() {
    local name="$1"
    local url="$2"
    local extract_dir="$3"
    local download_file="$4"
    local extract_method="$5"
    local max_retries=3
    local retry_count=0
    
    if [ ! -d "$extract_dir" ]; then
        mkdir -p "$extract_dir"
        if [ $? -ne 0 ]; then
            print_err "Failed to create directory: $extract_dir"
            return 1
        fi
    fi
    
    if [ -f "$download_file" ]; then
        print_info "File $(basename "$download_file") already exists."
        if is_yes "Do you want to skip the download process?"; then
            print_info "Skipping download..."
        else
            rm -f "$download_file"
            while [ $retry_count -lt $max_retries ]; do
                retry_count=$((retry_count + 1))
                print_info "Downloading $name... (Attempt $retry_count/$max_retries)"
                curl -L -o "$download_file" "$url" --http1.1
                if [ $? -eq 0 ] && [ -f "$download_file" ]; then
                    break
                else
                    print_err "Download attempt $retry_count failed"
                    rm -f "$download_file"
                    if [ $retry_count -eq $max_retries ]; then
                        print_err "Failed to download $name after $max_retries attempts"
                        return 1
                    fi
                    sleep 2
                fi
            done
        fi
    else
        while [ $retry_count -lt $max_retries ]; do
            retry_count=$((retry_count + 1))
            print_info "Downloading $name... (Attempt $retry_count/$max_retries)"
            curl -L -o "$download_file" "$url" --http1.1
            if [ $? -eq 0 ] && [ -f "$download_file" ]; then
                break
            else
                print_err "Download attempt $retry_count failed"
                rm -f "$download_file"
                if [ $retry_count -eq $max_retries ]; then
                    print_err "Failed to download $name after $max_retries attempts"
                    return 1
                fi
                sleep 2
            fi
        done
    fi
    
    if [ ! -f "$download_file" ]; then
        print_err "Downloaded file does not exist: $download_file"
        return 1
    fi
    
    cd "$extract_dir"
    if [ "$extract_method" == "unzip" ]; then
        print_info "Extracting with unzip..."
        unzip -q "$download_file"
        if [ $? -eq 0 ]; then
            print_success "Extraction completed successfully"
        else
            print_err "Extraction failed"
            cd - > /dev/null
            return 1
        fi
    else
        print_info "Extracting with tar..."
        tar xf "$download_file"
        if [ $? -eq 0 ]; then
            print_success "Extraction completed successfully"
        else
            print_err "Extraction failed"
            cd - > /dev/null
            return 1
        fi
    fi
    
    rm -f "$download_file"
    cd - > /dev/null
    
    return 0
}

setup_ndk() {
    local ndkUrl="https://github.com/Mohammed-Baqer-null/AndroidIDE-Rv2-ndk/releases/download/v27.1.12297006/android-ndk-r27b-aarch64.zip"
    local ndkVersion="27.1.12297006"
    
    # check architecture  
    if [[ "$ndk" == "true" ]]; then
        local arch="$(uname -m)"  
        if [ "$arch" != "aarch64" ]; then  
            npr "Unsupported architecture: $arch (only aarch64/arm64-v8a is supported)"  
            return 1  
        fi  
    
        if is_yes "Would you like to install and setup Android NDK"; then  
            # Ensure ndk dir exists in android-sdk  
            local ndk_base_dir="$HOME/android-sdk/ndk"
            local ndk_version_dir="$ndk_base_dir/$ndkVersion"
            local download_file="$HOME/android-ndk.zip"
            
            if [ ! -d "$ndk_base_dir" ]; then
                mkdir -p "$ndk_base_dir"
                if [ $? -ne 0 ]; then
                    npr "Failed to create NDK directory: $ndk_base_dir"
                    return 1
                fi
            fi
    
            # check if the ndk already exists  
            if ! ensure_ndk; then
                npr "Starting NDK download and installation..."
                if download_and_extract_ndk "Android NDK r27b" "$ndkUrl" "$ndk_base_dir" "$download_file" "unzip"; then
                    local extracted_dir=$(find "$ndk_base_dir" -maxdepth 1 -name "android-ndk-*" -type d | head -n 1)
                    if [ -n "$extracted_dir" ] && [ "$extracted_dir" != "$ndk_version_dir" ]; then
                        mv "$extracted_dir" "$ndk_version_dir"
                        if [ $? -eq 0 ]; then
                            npr "NDK directory renamed to: $ndk_version_dir"
                        else
                            npr "Warning: Could not rename NDK directory"
                        fi
                    fi
                    
                    if ensure_ndk; then
                        npr "Android NDK installation completed successfully!"
                        npr "NDK Location: $ndk_version_dir"
                    else
                        npr "NDK installation verification failed"
                        return 1
                    fi
                else
                    npr "NDK installation failed"
                    return 1
                fi
            else  
                npr "Ndk already downloaded"  
            fi  
        else  
            npr "Canceled"  
        fi
    fi
}

print_info() {
  # shellcheck disable=SC2059
  printf "${Blue}$1$Color_Off\n"
}

print_err() {
  # shellcheck disable=SC2059
  printf "${Red}$1$Color_Off\n"
}

print_warn() {
  # shellcheck disable=SC2059
  printf "${Orange}$1$Color_Off\n"
}

print_success() {
  # shellcheck disable=SC2059
  printf "${Green}$1$Color_Off\n"
}

is_yes() {

  msg=$1

  printf "%s ([y]es/[n]o): " "$msg"

  if [ "$assume_yes" == "true" ]; then
    ans="y"
    echo $ans
  else
    read -r ans
  fi

  if [[ "$ans" =~ $yes ]]; then
    return 0
  fi

  return 1
}

check_arg_value() {
  option_name="$1"
  arg_value="$2"
  if [[ -z "$arg_value" ]]; then
    print_err "No value provided for $option_name!" >&2
    exit 1
  fi
}

check_command_exists() {
  if command -v "$1" &>/dev/null; then
    return
  else
    print_err "Command '$1' not found!"
    exit 1
  fi
}

# shellcheck disable=SC2068
install_packages() {
  if [ "$assume_yes" == "true" ]; then
    $pkgm install $@ -y
  else
    $pkgm install $@
  fi
}

print_help() {
  echo "AndroidIDE build tools installer"
  echo "This script helps you easily install build tools in AndroidIDE."
  echo ""
  echo "Usage:"
  echo "${0} -s 34.0.4 -c -j 17"
  echo "This will install Android SDK 34.0.4 with command line tools and JDK 17."
  echo ""
  echo "Options :"
  echo "-i   Set the installation directory. Defaults to \$HOME."
  echo "-s   Android SDK version to download."
  echo "-c   Download Android SDK with command line tools."
  echo "-m   Manifest file URL. Defaults to 'manifest.json' in 'androidide-tools' GitHub repository."
  echo "-j   OpenJDK version to install. Values can be '17' or '21'"
  echo "-g   Install package: 'git'."
  echo "-o   Install package: 'git'."
  echo "-y   Assume \"yes\" as answer to all prompts and run non-interactively."
  echo ""
  echo "For testing purposes:"
  echo "-a   CPU architecture. Extracted using 'uname -m' by default."
  echo "-p   Package manager. Defaults to 'pkg'."
  echo "-l   Name of curl package that will be installed before starting installation process. Defaults to 'libcurl'."
  echo ""
  echo "-h   Prints this message."
}

download_and_extract() {
  # Display name to use in print messages
  name=$1

  # URL to download from
  url=$2

  # Directory in which the downloaded archive will be extracted
  dir=$3

  # Destination path for downloading the file
  dest=$4
  
  if [ $# -ge 5 ]; then
    extract_with=$5
  else
    extract_with="xz"
  fi

  if [ ! -d "$dir" ]; then
    mkdir -p "$dir"
  fi

  cd "$dir"

  do_download=true
  if [ -f "$dest" ]; then
    name=$(basename "$dest")
    print_info "File ${name} already exists."
    if is_yes "Do you want to skip the download process?"; then
      do_download=false
    fi
    echo ""
  fi

  if [ "$do_download" = "true" ]; then
    print_info "Downloading $name..."
    curl -L -o "$dest" "$url" --http1.1
    print_success "$name has been downloaded."
    echo ""
  fi

  if [ ! -f "$dest" ]; then
    print_err "The downloaded file $name does not exist. Cannot proceed..."
    exit 1
  fi

  # Extract the downloaded archive
  if [[ "$extract_with" == "xz" ]]; then
    print_info "Extracting downloaded archive with xz..."
    tar xvJf "$dest" && print_info "Extracted successfully"
  else
    print_info "Extracting downloaded archive with unzip..."
    unzip "$dest" && print_info "Extracted successfully"
  fi
  echo ""

  # Delete the downloaded file
  rm -vf "$dest"

  # cd into the previous working directory
  cd -
}

download_comp() {
  nm=$1
  jq_query=$2
  mdir=$3
  dname=$4

  # Extract the Android SDK URL
  print_info "Extracting URL for $nm from manifest..."
  url=$(jq -r "${jq_query}" "$downloaded_manifest")
  print_success "Found URL: $url"
  echo ""

  # Download and extract the Android SDK build tools
  download_and_extract "$nm" "$url" "$mdir" "$mdir/$dname.tar.xz" "xz"
}

## NOTE!
## When adding more installation configuration arguments,
# add them in com.itsaky.andridide.models.IdeSetupArgument as well
while [ $# -gt 0 ]; do
  case $1 in
  -c | --with-cmdline-tools)
    shift
    with_cmdline=false
    ;;
  -g | --with-git)
    shift
    pkgs+=" git"
    ;;
  -o | --with-openssh)
    shift
    pkgs+=" openssh"
    ;;
  -wn | --with-ndk)
    shift
    ndk=true
    ;;
  -y | --assume-yes)
    shift
    assume_yes=true
    ;;
  -i | --install-dir)
    shift
    check_arg_value "--install-dir" "${1:-}"
    install_dir="$1"
    ;;
  -m | --manifest)
    shift
    check_arg_value "--manifest" "${1:-}"
    manifest="$1"
    ;;
  -s | --sdk)
    shift
    check_arg_value "--sdk" "${1:-}"
    sdkver_org="$1"
    ;;
  -j | --jdk)
    shift
    check_arg_value "--jdk" "${1:-}"
    jdk_version="$1"
    ;;
  -a | --arch)
    shift
    check_arg_value "--arch" "${1:-}"
    arch="$1"
    ;;
  -p | --package-manager)
    shift
    check_arg_value "--package-manager" "${1:-}"
    pkgm="$1"
    ;;
  -l | --curl)
    shift
    check_arg_value "--curl" "${1:-}"
    pkg_curl="$1"
    ;;
  -h | --help)
    print_help
    exit 0
    ;;
  -*)
    echo "Invalid option: $1" >&2
    exit 1
    ;;
  *) break ;;
  esac
  shift
done

if [ "$arch" = "armv7l" ]; then
  arch="arm"
fi

# 64-bit CPU in 32-bit mode
if [ "$arch" = "armv8l" ]; then
  arch="arm"
fi

check_command_exists "$pkgm"

if [ "$jdk_version" == "21" ]; then
  print_warn "OpenJDK 21 support in AndroidIDE is experimental. It may or may not work properly."
  print_warn "Also, OpenJDK 21 is only supported in Gradle v8.4 and newer. Older versions of Gradle will NOT work!"
  if ! is_yes "Do you still want to install OpenJDK 21?"; then
    jdk_version="17"
    print_info "OpenJDK version has been reset to '17'"
  fi
fi

if [ "$jdk_version" != "17" ] && [ "$jdk_version" != "21" ]; then
  print_err "Invalid JDK version '$jdk_version'. Value can be '17' or '21'."
  exit 1
fi

sdk_version="_${sdkver_org//'.'/'_'}"

pkgs+=" $pkg_curl"

echo "------------------------------------------"
echo "Installation directory    : ${install_dir}"
echo "SDK version               : ${sdkver_org}"
echo "JDK version               : ${jdk_version}"
echo "With command line tools   : ${with_cmdline}"
echo "Extra packages            : ${pkgs}"
echo "CPU architecture          : ${arch}"
echo "------------------------------------------"

if ! is_yes "Confirm configuration"; then
  print_err "Aborting..."
  exit 1
fi

if [ ! -f "$install_dir" ]; then
  print_info "Installation directory does not exist. Creating directory..."
  mkdir -p "$install_dir"
fi

if [ ! command -v "$pkgm" ] &>/dev/null; then
  print_err "'$pkgm' command not found. Try installing 'termux-tools' and 'apt'."
  exit 1
fi

# Update repositories and packages
print_info "Update packages..."

$pkgm update
if [ "$assume_yes" == "true" ]; then
  $pkgm upgrade -y
else
  $pkgm upgrade
fi

# Install required packages
print_info "Installing required packages.."
# shellcheck disable=SC2086
install_packages $pkgs && print_success "Packages installed"
echo ""

# Download the manifest.json file
print_info "Downloading manifest file..."
downloaded_manifest="$install_dir/manifest.json"
curl -L -o "$downloaded_manifest" "$manifest" && print_success "Manifest file downloaded"
echo ""

# Install the Android SDK
download_comp "Android SDK" ".android_sdk" "$install_dir" "android-sdk"

# Install build tools
download_comp "Android SDK Build Tools" ".build_tools | .${arch} | .${sdk_version}" "$install_dir/android-sdk" "android-sdk-build-tools"

# Install platform tools
download_comp "Android SDK Platform Tools" ".platform_tools | .${arch} | .${sdk_version}" "$install_dir/android-sdk" "android-sdk-platform-tools"

if [ "$with_cmdline" = true ]; then
  # Install the Command Line tools
  download_comp "Command-line tools" ".cmdline_tools" "$install_dir/android-sdk" "cmdline-tools"
fi

# Install JDK
print_info "Installing package: 'openjdk-$jdk_version'"
install_packages "openjdk-$jdk_version" && print_info "JDK $jdk_version has been installed."

jdk_dir="$SYSROOT/opt/openjdk"

print_info "Updating ide-environment.properties..."
print_info "JAVA_HOME=$jdk_dir"
echo ""
props_dir="$SYSROOT/etc"
props="$props_dir/ide-environment.properties"

if [ ! -d "$props_dir" ]; then
  mkdir -p "$props_dir"
fi

if [ ! -e "$props" ]; then
  printf "JAVA_HOME=%s" "$jdk_dir" >"$props" && print_success "Properties file updated successfully!"
else
  if is_yes "$props file already exists. Would you like to overwrite it?"; then
    printf "JAVA_HOME=%s" "$jdk_dir" >"$props" && print_success "Properties file updated successfully!"
  else
    print_err "Manually edit $SYSROOT/etc/ide-environment.properties file and set JAVA_HOME and ANDROID_SDK_ROOT."
  fi
fi

setup_ndk

rm -vf "$downloaded_manifest"
print_success "Downloads completed. You are ready to go!"