#!/bin/sh

set -e

require_clean_work_tree () {
    return

  # Update the index
  git update-index -q --ignore-submodules --refresh
  err=0

  # Disallow unstaged changes in the working tree
  if ! git diff-files --quiet --ignore-submodules --
  then
    echo >&2 "Cannot $1: you have unstaged changes."
    git diff-files --name-status -r --ignore-submodules -- >&2
    err=1
  fi

  # Disallow uncommitted changes in the index
  if ! git diff-index --cached --quiet HEAD --ignore-submodules --
  then
    echo >&2 "Cannot $1: your index contains uncommitted changes."
    git diff-index --cached --name-status -r --ignore-submodules HEAD -- >&2
    err=1
  fi

  if [ $err = 1 ]
  then
    echo >&2 "Please commit or stash them prior to creating release."
    exit 1
  fi
}

get_package_version() {
  echo $(cat package.json \
  | grep version \
  | head -1 \
  | awk -F: '{ print $2 }' \
  | sed 's/[",]//g' \
  | tr -d '[[:space:]]')
}

bump_version () {
  echo ""
  select versionBumpType in "major" "minor" "patch"; do
    case $versionBumpType in
      major ) break;;
      minor ) break;;
      patch ) break;;
    esac
  done

  echo "\nBumped package version to: $(npm version --no-git-tag-version $versionBumpType)"

  sleep 2
}

upload_release_to_sentry () {
  local RELEASE_ID=$1
  local APP_NAME=$2
  local SOURCE_MAP_URL=$3

  local releaseStatusCode=$(curl -o /dev/null --silent --write-out '%{http_code}' -H "Authorization: Bearer $SENTRY_AUTH_TOKEN" "https://app.getsentry.com/api/0/projects/$SENTRY_TEAM/$SENTRY_PROJECT/releases/$RELEASE_ID/")

  if [ "$releaseStatusCode" != "404" ]; then
    echo "Delete existing Sentry release?"
    select yn in "Yes" "No"; do
      case $yn in
        Yes ) echo "\nDeleting existing Sentry release for this version."
              curl "https://app.getsentry.com/api/0/projects/$SENTRY_TEAM/$SENTRY_PROJECT/releases/$RELEASE_ID/" \
                -k \
                --progress-bar \
                -H "Authorization: Bearer $SENTRY_AUTH_TOKEN" \
                -X DELETE > /dev/null;
              break;;
        No ) break;;
      esac
    done
  fi

  echo "Creating Sentry Release:"
  # Creates the release
  curl "https://app.getsentry.com/api/0/projects/$SENTRY_TEAM/$SENTRY_PROJECT/releases/" \
    -k \
    --progress-bar \
    -H "Authorization: Bearer $SENTRY_AUTH_TOKEN" \
    -X POST \
    -d "{\"version\": \"$RELEASE_ID\"}" \
    -H 'Content-Type: application/json' > /dev/null

  echo "\nUploading source to Sentry:"
  # upload source
  curl "https://app.getsentry.com/api/0/projects/$SENTRY_TEAM/$SENTRY_PROJECT/releases/$RELEASE_ID/files/" \
    -k \
    --progress-bar \
    -H "Authorization: Bearer $SENTRY_AUTH_TOKEN" \
    -X POST \
    -F file=@./.release/$PLATFORM/bundle \
    -F name="/$APP_NAME.bundle" > /dev/null

  echo "\nUploading source map to Sentry:"
  # upload source map
  curl "https://app.getsentry.com/api/0/projects/$SENTRY_TEAM/$SENTRY_PROJECT/releases/$RELEASE_ID/files/" \
    -k \
    --progress-bar \
    -H "Authorization: Bearer $SENTRY_AUTH_TOKEN" \
    -X POST \
    -F file=@./.release/$PLATFORM/map \
    -F name="/$APP_NAME.map" > /dev/null
}

create_release () {
  if [ "$SENTRY_AUTH_TOKEN" == "" ]; then
    echo >&2 "Must specify Sentry authentication token."
    exit 1;
  fi

  if [ "$PLATFORM" != 'ios' ] && [ "$PLATFORM" != 'android' ]; then
    echo >&2 "Platform must be specified ('ios' or 'android')."
    exit 1;
  fi

  if [ "$SENTRY_TEAM" == "" ] || [ "$SENTRY_PROJECT" == "" ]; then
    echo >&2 "Must specify the Sentry team and project."
    exit 1;
  fi

  echo "Checking for clean work tree..."
  require_clean_work_tree 'create release'

  echo "\nPublishing a release for '$PLATFORM' platform on the '$SENTRY_TEAM/$SENTRY_PROJECT' Sentry project..."

  local XDE_PORT=$(exp url --localhost | grep localhost | sed 's/.*://')

  local CURRENT_PACKAGE_VERSION=$(get_package_version)
  echo "\nCurrent version: v$CURRENT_PACKAGE_VERSION"

  echo "Bump version?"
  select yn in "Yes" "No"; do
    case $yn in
      Yes ) bump_version; break;;
      No ) break;;
    esac
  done

  local RELEASE_ID=$(get_package_version)

  echo "\nReleasing $RELEASE_ID...";

  mkdir -p "./.release/$PLATFORM"

  local BASE_URL=$(\
      curl -k -f -H "exponent-platform: $PLATFORM" "http://localhost:$XDE_PORT" \
          | sed "s/.*\"\(http.*\)\.bundle.*/\1/g")

  echo "\nFetching build from XDE...(may take a while, due to minify)"
  {
      curl "$BASE_URL.bundle?platform=$PLATFORM&dev=false&hot=false&minify=true" \
      -k \
      -f \
      --progress-bar \
      -o "./.release/$PLATFORM/bundle" \
      -H "exponent-platform: $PLATFORM" 1> /dev/null
  } || {
    echo >&2 "\n\033[0;31mError fetching build from XDE. Please check your XDE port and that XDE is running."
    exit 1
  }

  echo "\nFetching source map from XDE..."
  {
    curl "$BASE_URL.map?platform=$PLATFORM&dev=false&hot=false&minify=true&flattenSourceMap=true" \
      -k \
      -f \
      --progress-bar \
      -o "./.release/$PLATFORM/map" \
      -H "exponent-platform: $PLATFORM" 1> /dev/null
  } || {
    echo >&2 "\n\033[0;31mError fetching source map from XDE. Please check your XDE port and that XDE is running."
    exit 1
  }

  echo "\nModifying bundle and source map..."

  local APP_NAME=$(cat ./.release/$PLATFORM/bundle | perl -n -e'/\/\/# sourceMappingURL=(\/.*)?\/(.*).map/ && print $2')

  # make sure it just says "/APP_NAME.map" as the source map URL
  perl -i -p -e"s/\/\/# sourceMappingURL=\/(.*).map(.*)/\/\/# sourceMappingURL=\/$APP_NAME.map/gm" ./.release/$PLATFORM/bundle

  # remove pwd from source map
  # path_to_strip=$(pwd | sed -e 's/[]\/$*.^|[]/\\&/g')
  # perl -i -p -e"s/$path_to_strip\///gm" ./.release/$PLATFORM/map

  # remove query parameters from bundle filename in source map
  perl -i -p -e"s/\\.bundle?[^\"]*/\\.bundle/gm" ./.release/$PLATFORM/map

  upload_release_to_sentry $RELEASE_ID $APP_NAME

  rm -rf ./.release

  echo "\n==============================================================="
  echo "\nIf you change code between now and uploading to exp.host, be sure to run this script again!"

  echo "--Fin"
}

usage () {
  echo "usage: publish-sentry-release [[[-p platform ] [-t sentry team] [-P sentry project] [-k sentry auth token]] | [-h]]"
}

PLATFORM=
SENTRY_TEAM=
SENTRY_PROJECT=
SENTRY_AUTH_TOKEN=

while [ "$1" != "" ]; do
  case $1 in
    -p | --platform )   shift
                        PLATFORM=$1
                        ;;
    -t | --team )       shift
                        SENTRY_TEAM=$1
                        ;;
    -P | --project )    shift
                        SENTRY_PROJECT=$1
                        ;;
    -k | --auth-token ) shift
                        SENTRY_AUTH_TOKEN=$1
                        ;;
    -h | --help )       usage
                        exit
                        ;;
    * )                 usage
                        exit 1
                        ;;
  esac
  shift
done

create_release
