#!/bin/bash

set -e -o pipefail

: "${REMOVE_OLD_MODS:=false}"
: "${MODS_FILE:=}"
: "${REMOVE_OLD_MODS_DEPTH:=1} "
: "${REMOVE_OLD_MODS_INCLUDE:=*.jar,*-version.json}"
sum_file=/data/.generic_pack.sum

# shellcheck source=start-utils
. "${SCRIPTS:-/}start-utils"
isDebugging && set -x

#  CURSE_URL_BASE used in manifest downloads below
CURSE_URL_BASE=${CURSE_URL_BASE:-https://minecraft.curseforge.com/projects}

# Remove old mods/plugins
if isTrue "${REMOVE_OLD_MODS}" && [ -z "${MODS_FILE}" ]; then
  removeOldMods /data/mods
  removeOldMods /data/plugins
  rm -f "$sum_file"
fi

# If packwiz url passed, bootstrap packwiz and update mods before other modpack processing
if [[ "${PACKWIZ_URL:-}" ]]; then
  # Ensure we have the latest packwiz bootstrap installer
  if [[ "${GH_TOKEN:-}" ]]; then
    # User has provided a Personal Access Token to mitigate rate-limiting issues
    oAuthScopes="undefined"
    oAuthScopes=$(curl -sv -H "Authorization: token $GH_TOKEN" https://api.github.com/users/codertocat -I | grep x-oauth-scopes)
    if [[ ! "$oAuthScopes" =~ ^x-oauth-scopes:[[:space:]]*$ ]]; then
      # Don't use what you don't have to...
      log "ERROR: GH_TOKEN has permissions it doesn't need. Recreate or update this personal access token and disable ALL scopes."
      exit 1
    else
      latestPackwiz=$(curl -fsSL -H "Authorization: token $GH_TOKEN" https://api.github.com/repos/packwiz/packwiz-installer-bootstrap/releases/latest)
    fi
  else
    latestPackwiz=$(curl -fsSL https://api.github.com/repos/packwiz/packwiz-installer-bootstrap/releases/latest)
  fi
  if [[ -z "${latestPackwiz}" ]]; then
    log "WARNING: Could not retrieve Packwiz bootstrap installer release information"
  else
    isDebugging && log "Latest packwiz ${latestPackwiz}"
    latestPackwizVer=$(echo "${latestPackwiz}" | jq --raw-output '.tag_name')
    latestPackwizUrl=$(echo "${latestPackwiz}" | jq --raw-output '.assets[] | select(.name | match("packwiz-installer-bootstrap.jar")) | .url')
   : "${PACKWIZ_BOOTSTRAP_JAR:=packwiz-installer-bootstrap_${latestPackwizVer}.jar}"
   if [[ ! -e $PACKWIZ_BOOTSTRAP_JAR ]]; then
      log "Downloading Packwiz ${latestPackwizVer}"
      if ! curl -H "Accept:application/octet-stream" -o "$PACKWIZ_BOOTSTRAP_JAR" -fsSL ${latestPackwizUrl}; then
        log "ERROR: failed to download Packwiz bootstrap installer"
        exit 1
      fi
    fi
  fi
  log "Running packwiz installer against URL: ${PACKWIZ_URL}"
  java -jar "${PACKWIZ_BOOTSTRAP_JAR}" -g -s server "${PACKWIZ_URL}"
  #if bootstrap download fails, download installer manually - then run without updating
  returnVal=$?
  if [[ $returnVal ]]; then
    latestPackwizInstaller=$(curl -fsSL https://api.github.com/repos/packwiz/packwiz-installer/releases/latest)
    latestPackwizInstallerVer=$(echo "${latestPackwizInstaller}" | jq --raw-output '.tag_name')
    latestPackwizInstallerUrl=$(echo "${latestPackwizInstaller}" | jq --raw-output '.assets[] | select(.name | match("packwiz-installer.jar")) | .url')
    log "Packwiz couldn't update - Downloading Packwiz Installer ${latestPackwizInstallerVer}"
    curl -H "Accept:application/octet-stream" -o "packwiz-installer.jar" -fsSL "${latestPackwizInstallerUrl}"
    java -jar "${PACKWIZ_BOOTSTRAP_JAR}" -g -bootstrap-no-update -s server "${PACKWIZ_URL}"
  fi
fi

# If supplied with a URL for a modpack (simple zip of jars), download it and unpack
if [[ "$MODPACK" ]]; then
  if isURL "${MODPACK}"; then
    log "Downloading mod/plugin pack"
    if ! get -o /tmp/modpack.zip "${MODPACK}"; then
      log "ERROR: failed to download from ${MODPACK}"
      exit 2
    fi
  elif [[ "$MODPACK" =~ .*\.zip ]]; then
    if ! cp "$MODPACK" /tmp/modpack.zip; then
      log "ERROR: failed to copy from $MODPACK"
      exit 2
    fi
  else
    log "ERROR Invalid URL or Path given for MODPACK: $MODPACK"
    exit 1
  fi

  if [ "$FAMILY" = "SPIGOT" ]; then
    mkdir -p /data/plugins
    if ! unzip -o -d /data/plugins /tmp/modpack.zip; then
      log "ERROR: failed to unzip the modpack from ${MODPACK}"
    fi
  else
    mkdir -p /data/mods
    if ! unzip -o -d /data/mods /tmp/modpack.zip; then
      log "ERROR: failed to unzip the modpack from ${MODPACK}"
    fi
  fi
  rm -f /tmp/modpack.zip

elif [[ "$MODS" ]]; then
  if [ "$FAMILY" = "SPIGOT" ]; then
    out_dir=/data/plugins
  else
    out_dir=/data/mods
  fi
  mkdir -p "$out_dir"

  for i in ${MODS//,/ }
  do
    if isURL "$i"; then
      log "Downloading mod/plugin $i ..."
      if ! get --skip-up-to-date -o "${out_dir}" "$i"; then
        log "ERROR: failed to download from $i into $out_dir"
        exit 2
      fi
    elif [[ -f "$i" && "$i" =~ .*\.jar ]]; then
      log "Copying plugin located at $i ..."
      out_file=$(basename "$i")
      if ! cp "$i" "${out_dir}/$out_file"; then
        log "ERROR: failed to copy from $i into $out_dir"
        exit 2
      fi
    elif [[ -d "$i" ]]; then
      log "Copying plugin jars from $i ..."
      cp "$i"/*.jar "${out_dir}"
    else
      log "ERROR Invalid URL or path given in MODS: $i"
      exit 2
    fi
  done

elif [[ "$MODS_FILE" ]]; then
  if [ ! -f "$MODS_FILE" ]; then
    log "ERROR: given MODS_FILE file does not exist"
    exit 2
  fi

  if [ "$FAMILY" = "SPIGOT" ]; then
    out_dir=/data/plugins
  else
    out_dir=/data/mods
  fi
  mkdir -p "$out_dir"

  args=(
    -o "${out_dir}"
    --log-progress-each
    --skip-up-to-date
    --uris-file "${MODS_FILE}"
  )
  if isTrue "${REMOVE_OLD_MODS}"; then
    args+=(
    --prune-others "${REMOVE_OLD_MODS_INCLUDE}"
    --prune-depth "${REMOVE_OLD_MODS_DEPTH}"
    )
  fi

  if ! get "${args[@]}" ; then
    log "ERROR: failed to retrieve one or more mods"
    exit 1
  fi
fi

if [[ "$MANIFEST" ]]; then
    if [[ -e "$MANIFEST" ]]; then
        EFFECTIVE_MANIFEST_FILE=$MANIFEST
    elif isURL "$MANIFEST"; then
        EFFECTIVE_MANIFEST_FILE=/tmp/manifest.json
        EFFECTIVE_MANIFEST_URL=$(curl -Ls -o /dev/null -w %{effective_url} $MANIFEST)
        curl -Ls -o $EFFECTIVE_MANIFEST_FILE "$EFFECTIVE_MANIFEST_URL"
    else
        log "MANIFEST='$MANIFEST' is not a valid manifest url or location"
        exit 2
    fi

case "X$EFFECTIVE_MANIFEST_FILE" in
  X*.json)
    if [ -f "${EFFECTIVE_MANIFEST_FILE}" ]; then
      MOD_DIR=${FTB_BASE_DIR:-/data}/mods
      if [ ! -d "$MOD_DIR" ]
      then
        log "Creating mods dir $MOD_DIR"
        mkdir -p "$MOD_DIR"
      fi
      log "Starting manifest download..."
      cat "${EFFECTIVE_MANIFEST_FILE}" | jq -r '.files[] | (.projectID|tostring) + " " + (.fileID|tostring)'| while read -r p f
      do
        if [ ! -f $MOD_DIR/${p}_${f}.jar ]
        then
          redirect_url="$(curl -Ls -o /dev/null -w %{effective_url} ${CURSE_URL_BASE}/${p})"
          url="$redirect_url/download/${f}/file"
          log Downloading curseforge mod $url
          #  Manifest usually doesn't have mod names. Using id should be fine, tho
          curl -sSL "${url}" -o $MOD_DIR/${p}_${f}.jar
        fi
      done
    else
      log "Could not find manifest file, insufficient privileges, or malformed path."
    fi
    ;;
  *)
    log "Invalid manifest file for modpack. Please make sure it is a .json file."
    ;;
esac
fi

function genericPacks() {
  : "${GENERIC_PACKS:=${GENERIC_PACK}}"
  : "${GENERIC_PACKS_PREFIX:=}"
  : "${GENERIC_PACKS_SUFFIX:=}"

  if [[ "${GENERIC_PACKS}" ]]; then
    IFS=',' read -ra packs <<< "${GENERIC_PACKS}"

    packFiles=()
    for packEntry in "${packs[@]}"; do
      pack="${GENERIC_PACKS_PREFIX}${packEntry}${GENERIC_PACKS_SUFFIX}"
      if isURL "${pack}"; then
        mkdir -p /data/packs
        log "Downloading generic pack from $pack"
        if ! outfile=$(get -o /data/packs --output-filename --skip-up-to-date "$pack"); then
          log "ERROR: failed to download $pack"
          exit 2
        fi
        packFiles+=("$outfile")
      else
        packFiles+=("$pack")
      fi
    done

    isDebugging && [ -f "$sum_file}" ] && cat "$sum_file"

    log "Checking if generic packs are up to date"
    if isTrue "${SKIP_GENERIC_PACK_UPDATE_CHECK:-false}" && [ -f "$sum_file" ]; then
      log "Skipping generic pack update check"
    elif isTrue "${FORCE_GENERIC_PACK_UPDATE}" || ! checkSum "${sum_file}"; then
      log "Generic pack(s) are out of date. Re-applying..."

      original_base_dir=/data/.tmp/generic_pack_base
      base_dir=$original_base_dir
      rm -rf "${base_dir}"
      mkdir -p "${base_dir}"
      for pack in "${packFiles[@]}"; do
        isDebugging && ls -l "${pack}"
        extract "${pack}" "${base_dir}"
      done

      # recalculate the actual base directory of content
      if ! base_dir=$(mc-image-helper find \
          --max-depth=3 --type=directory --name=mods,plugins,config \
          --only-shallowest --fail-no-matches --format '%h' \
          "$base_dir"); then
        log "ERROR: Unable to find content base of generic packs ${GENERIC_PACKS}. Directories:"
        mc-image-helper find --name=* --max-depth=3 --type=directory --format '- %P' "$original_base_dir"
        exit 1
      fi

      if [ -f /data/manifest.txt ]; then
        log "Manifest exists from older generic pack, cleaning up ..."
        while read -r f; do
          rm -rf "/data/${f}"
        done < /data/manifest.txt
        # prune empty dirs
        find /data -mindepth 1 -depth -type d -empty -delete
        rm -f /data/manifest.txt
      fi

      log "Writing generic pack manifest ... "
      find "${base_dir}" -type f -printf "%P\n" > /data/manifest.txt

      log "Applying generic pack ..."
      cp -R -f "${base_dir}"/* /data
      rm -rf $original_base_dir

      log "Saving generic pack(s) checksum"
      sha1sum "${packFiles[@]}" > "${sum_file}"
      isDebugging && cat "$sum_file"
    fi
  fi
}

function modrinthProjects() {
  : "${MODRINTH_PROJECTS:=}"
  : "${MODRINTH_DOWNLOAD_OPTIONAL_DEPENDENCIES:=true}"
  : "${MODRINTH_ALLOWED_VERSION_TYPE:=release}"

  if [[ $MODRINTH_PROJECTS ]] && isFamily HYBRID FABRIC; then
    if [[ ${FAMILY^^} = HYBRID ]]; then
      loader=forge
    else
      loader="${FAMILY,,}"
    fi
    mc-image-helper modrinth \
      --output-directory=/data \
      --projects="${MODRINTH_PROJECTS}" \
      --game-version="${VANILLA_VERSION}" \
      --loader="$loader" \
      --download-optional-dependencies="$MODRINTH_DOWNLOAD_OPTIONAL_DEPENDENCIES" \
      --allowed-version-type="$MODRINTH_ALLOWED_VERSION_TYPE"
  fi
}

genericPacks

modrinthProjects

exec "${SCRIPTS:-/}start-setupModconfig" "$@"
