#!/usr/bin/env bash

set -eu
set -o pipefail

function show_help() {
  echo "Usage:"
  echo "  install-simd-package [-m|--arch ARCH] [-s|--os SYSTEM] [-t|--variant VARIANT] [-d|--dl-only] [-n|--dry-run] [--rm] PACKAGE [VERSION] [OPTION...]"
  echo "  install-simd-package -l|--list PACKAGE"
  echo "  install-simd-package -L|--list-all"
}

function get_host_os() {
    if ! [ -f /etc/os-release ]; then
        echo "unknown"
        return
    fi

    local os_id os_version os_codename

    os_id="$(awk -F= '$1=="ID" { print $2 ;}' /etc/os-release | tr -d \")"
    os_version="$(awk -F= '$1=="VERSION_ID" { print $2 ;}' /etc/os-release | tr -d \")"
    os_codename="$(awk -F= '$1=="VERSION_CODENAME" { print $2 ;}' /etc/os-release | tr -d \")"

    case "$os_id" in
        centos|rhel|redhat)
            echo "el${os_version}"
            ;;
        debian)
            echo "$os_codename" | tr '[:upper:]' '[:lower:]'
            ;;
        fedora)
            echo "fc${os_version}"
            ;;
        ubuntu)
            echo "$os_codename" | tr '[:upper:]' '[:lower:]'
            ;;
        sles|opensuse*)
            suse_version="${os_version%%-*}"
            suse_version="${suse_version%%.*}"
            echo "suse${suse_version}"
            ;;
        *)
            echo "unknown"
            ;;
    esac
}


if ! hash curl stow 2>/dev/null; then
  echo "Cannot proceed without curl and stow. Abort"
  exit 1
fi

server="${SIMD_SERVER_URL:-https://packages.simd.stream}"
gpg_key="70DAEE7AC70C162C258494805A8A4D024DF20559"
gpg_server="hkps://keys.openpgp.org"

dl_dir="${SIMD_DL_DIR:-$HOME/Downloads}"
install_dir="${SIMD_PKGS_DIR:-$HOME/local/packages}"

arch="$(uname -m)"
os="$(uname -s)"
version="latest"
variant=""
options=""

remove_dl="no"
dl_only="no"
dry_run="no"
list_only="no"
list_all="no"

while [ -n "${1:-}" ]; do
  case "$1" in
    -m|--arch)
      arch="$2"
      shift 2
      ;;
    -s|--os)
      os="$2"
      shift 2
      ;;
    -t|--variant)
      variant="$2"
      shift 2
      ;;
    -d|--dl-only)
      dl_only="yes"
      shift
      ;;
    --rm)
      remove_dl="yes"
      dl_dir="/tmp/packages-$$"
      shift
      ;;

    -n|--no|--dry-run)
      dry_run="yes"
      shift
      ;;
    -l|--list)
      list_only="yes"
      shift
      ;;
    -L|--list-all)
      list_only="yes"
      list_all="yes"
      shift
      ;;

    -h|--help)
      show_help
      exit
      ;;
    *)
      break
      ;;
  esac
done

# --list-all doesn't require a package name
if [ "$list_only" = "yes" ] && [ "$list_all" = "yes" ]; then
  curl -L "${server}/INDEX"
  exit
fi

if [ "$#" -lt 1 ]; then
  show_help
  exit 2
fi
package="$1"

if [ "$list_only" = "yes" ]; then
  curl -sSL "${server}/INDEX" | grep "$package"
  exit
fi

[ "$#" -ge 2 ] && version="$2"
[ "$#" -gt 2 ] && options="${*:3}"
noptions_requested="$(wc -w <<<"$options")"

index="INDEX"
[ "$version" = "latest" ] && index+='.latest'

pkglist="$(curl -s "${server}/${index}")"

set +e # We handle the case where there are no candidates belo
candlist="$(grep -E "^$package +$version + $arch +$os +$variant" <<<"$pkglist")"
set -e

readarray -t candidates <<<"$candlist"
matches=()
for c in "${candidates[@]}"; do
  # Each package line has 6 standard fields; the remaining ones are options
  noptions_candidate=$(( $(wc -w <<<"$c") - 6 ))

  # A match will contains the requested options...
  for o in $options; do
    ! grep -q "$o" <<<"$c" && continue 2
  done

  # ...and not any other options
  [ "$noptions_candidate" -eq "$noptions_requested" ] && matches+=("$c")
done

# If there are several OS variants, prefer the host's OS first, then static
if [ ${#matches[@]} -gt 1 ]; then
    host_os="$(get_host_os)"

    if [ "$(printf -- '%s\n' "${matches[@]}" | grep -c "$host_os")" -eq 1 ]; then
        echo "Using version for detected platform: $host_os"
        matches=( "$(printf -- '%s\n' "${matches[@]}" | grep "$host_os")" )
    elif [ "$(printf -- '%s\n' "${matches[@]}" | grep -c "static")" -eq 1 ]; then
        echo "Using static version (no version available for detected platform: $host_os)"
        matches=( "$(printf -- '%s\n' "${matches[@]}" | grep "static")" )
    fi
fi

if [ ${#matches[@]} -eq 0 ]; then
  cat <<EOM
No candidate matches your package request.
Your request:
  pkg: $package
  version: $version
  arch: $arch
  os: $os
  variant: $variant
  options: $options
EOM
  exit 10
elif [ ${#matches[@]} -gt 1 ]; then
  cat <<EOM
More than one candidate matches your package request.
Your request:
  pkg: $package
  version: $version
  arch: $arch
  os: $os
  variant: $variant
  options: $options
Candidates:
  ${matches[*]}
This should never happen. Abort.
EOM
  exit 11
fi

echo -n "Chosen variant: "; tr -s ' ' <<<"${matches[0]}"

[ "$dry_run" = "yes" ] && exit

server_path="$(awk '{print $6}' <<<"${matches[0]}")"
fname="$(basename "$server_path")"
fname_sha="${fname}.sha256"
fname_sig="${fname}.sig"

if [ ! -d "$dl_dir" ]; then
  echo "Created download directory: $dl_dir"
  mkdir -p "$dl_dir"
fi
cd "$dl_dir"

echo "Downloading ${package}-${version}-${arch}-${os}${variant:+-$variant}..."

rm -f "$fname_sha"
curl -# -O "${server}/${server_path}.sha256"

if ! sha256sum -c --status "$fname_sha" 2>/dev/null; then
  rm -f "$fname"
  curl -# -O "${server}/$server_path"
fi

if ! sha256sum -c "$fname_sha"; then
  echo "Downloaded file checksum does not match. Abort."
  exit 12
fi

if hash gpg 2>/dev/null; then
  # If we don't already have the public key, import it
  if ! gpg --list-keys "$gpg_key" &>/dev/null; then
    gpg --keyserver "$gpg_server" --recv-keys "$gpg_key" && \
    echo "Consider trusting the Drone key: gpg --edit-key $gpg_key --> trust" || \
    true
  fi

  # If the key is still not present, then it must have failed to import (this happens on old gpg versions)
  # Don't abort processing in this case
  if ! gpg --list-keys "$gpg_key" &>/dev/null; then
    echo "Failed to import Drone key (this happens on old gpg versions). Proceeding without verifying..."
  else
    rm -f "$fname_sig"
    if curl -O --silent --fail "${server}/${server_path}.sig"; then
      if ! gpg --verify "$fname_sig" "$fname"; then
        exit 13
      fi
    else
      echo "No signature available for $fname"
    fi
  fi
fi

[ "$dl_only" = "yes" ] && exit

if [ ! -d "$install_dir" ]; then
  echo "Created install directory: $install_dir"
  mkdir -p "$install_dir"
fi
cd "$install_dir"

folder_name="$(head -1 <(tar tf "${dl_dir}/${fname}"))"
if [ -d "$folder_name" ]; then
  echo "Package already exists: $folder_name"
  echo "Abort."
  exit 14
fi

tar xf "${dl_dir}/${fname}"
for d in "$package"-*; do
  stow -D "$d"
done
stow --no-folding "$folder_name"

if [ "$remove_dl" = "yes" ]; then
  if [[ "$dl_dir" =~ /tmp.* ]]; then
    rm -rf "$dl_dir"
  else
    rm -f "${dl_dir}/${fname}"
    rm -f "${dl_dir}/${fname_sha}"
  fi
fi
