#!/bin/bash

if ! command -v jq &> /dev/null; then
	echo "jq - the commandline JSON processor - is required dependency, please install it on your system..."
	exit
fi

QUOTED_ARGS=$(printf " %q" "$@")
ORIGINAL_COMMAND="$0$QUOTED_ARGS"
handle_interrupt() {
  echo "Upload script interrupted" >&2
  echo "To continue, try running: ${RETRY_COMMAND:-$ORIGINAL_COMMAND}" >&2
  exit 1
}
trap handle_interrupt SIGINT

parse_from_json() {
	echo "$1" | jq -r ".$2"
}

print_response_verbose() {
  if ((VERBOSE)); then
    echo "Request: $1 $2"
    echo "Body: $3"
    echo "Response: $4"
    echo "Body: $5"
  fi
}

FILES=()

for ARG in "$@"; do
	case "$ARG" in

		--login=*)
		LOGIN="${ARG#*=}"
		;;

		--api-token=*)
		API_TOKEN="${ARG#*=}"
		;;

		--auth-token=*)
		AUTH_TOKEN="${ARG#*=}"
		;;

		--folder-slug=*)
		FOLDER_SLUG="${ARG#*=}"
		;;

		--retry-slug=*)
		RETRY_SLUG="${ARG#*=}"
		;;

		--api-host=*)
		API_HOST="${ARG#*=}"
		;;

		--verbose)
		VERBOSE=1
		;;

		*)
		FILES+=("$ARG")
		;;
	esac
done

if [[ "${FILES[*]}" == '' || "$LOGIN" == '' || "$AUTH_TOKEN" == '' ]]; then
	echo "Usage ./upload.sh --login=LOGIN --auth-token=AUTH_TOKEN [--folder-slug=FOLDER_SLUG] [--verbose] [--api-token=API_KEY] [--retry-slug=RETRY_SLUG] [--api-host=API_HOST] files..." >&2
	exit 2
fi

API_TOKEN=${API_TOKEN:-';HG%7jW6@6/8vx">R;f('}
API_HOST=${API_HOST:-"apis.uloz.to"}
API_URL="https://$API_HOST"
RETRY_COMMAND="$ORIGINAL_COMMAND"
RETRY_SLUG=${RETRY_SLUG:-''}
if [[ "$RETRY_SLUG" != '' ]]; then
  IS_RERUN=1
fi

AUTH_HEADER="X-Auth-Token: $API_TOKEN"
CONTENT_TYPE_HEADER="Content-type: application/json"
ACCEPT_HEADER="Accept: application/json"

TEMPDIR=$(mktemp -d)
trap "rm -rf $TEMPDIR" EXIT


echo "User $LOGIN authentication"
SESSION_REQUEST="{\"login\":\"$LOGIN\",\"token\":\"$AUTH_TOKEN\"}"
SESSION_URL="$API_URL/v5/auth/token"
RESPONSE_FILE="$TEMPDIR/response"

METHOD=POST
SESSION_RESPONSE_CODE=$(curl -s \
  -o "$RESPONSE_FILE" \
  -w "%{http_code}" \
	-X $METHOD \
	-H "$AUTH_HEADER" \
	-H "$CONTENT_TYPE_HEADER" \
	-H "$ACCEPT_HEADER" \
	-d "$SESSION_REQUEST" \
	"$SESSION_URL")
SESSION_RESPONSE=$(cat "$RESPONSE_FILE" 2> /dev/null)

print_response_verbose "$METHOD" "$SESSION_URL" "<hidden>" "$SESSION_RESPONSE_CODE" "<hidden>"

USER_TOKEN=$(parse_from_json "$SESSION_RESPONSE" token_id)

if [[ "$USER_TOKEN" == null || "$USER_TOKEN" == '' ]]; then
	echo 'User authentication failed' >&2
	exit 1
fi
USER_TOKEN_HEADER="X-User-Token: $USER_TOKEN"
echo "Authentication successful"

echo "Fetching upload link"
if [[ "$RETRY_SLUG" != '' ]]; then
  UPLOAD_LINK_REQUEST="{\"user_login\":\"$LOGIN\",\"private_slug\":\"$RETRY_SLUG\"}"
else
  UPLOAD_LINK_REQUEST="{\"user_login\":\"$LOGIN\"}"
fi
UPLOAD_LINK_URL="$API_URL/v6/upload/link"
METHOD=POST
UPLOAD_LINK_RESPONSE_CODE=$(curl -s \
  -o "$RESPONSE_FILE" \
  -w "%{http_code}" \
	-X $METHOD \
	-H "$AUTH_HEADER" \
	-H "$CONTENT_TYPE_HEADER" \
	-H "$ACCEPT_HEADER" \
	-H "$USER_TOKEN_HEADER" \
	-d "$UPLOAD_LINK_REQUEST" \
	"$UPLOAD_LINK_URL")
UPLOAD_LINK_RESPONSE=$(cat "$RESPONSE_FILE" 2> /dev/null)

print_response_verbose "$METHOD" "$UPLOAD_LINK_URL" "$UPLOAD_LINK_REQUEST" "$UPLOAD_LINK_RESPONSE_CODE" "$UPLOAD_LINK_RESPONSE"

UPLOAD_LINK=$(parse_from_json "$UPLOAD_LINK_RESPONSE" upload_url)
BATCH_PRIVATE_SLUG=$(parse_from_json "$UPLOAD_LINK_RESPONSE" private_slug)

if [[ "$UPLOAD_LINK" == null || "$UPLOAD_LINK" == '' || "$BATCH_PRIVATE_SLUG" == null || "$BATCH_PRIVATE_SLUG" == '' ]]; then
	echo 'Upload link fetch failed' >&2
	handle_interrupt
fi
echo "Upload link fetched"

if ((IS_RERUN)); then
  echo "Retrieving completed file ids"
  VIEW_BATCH_URL="$API_URL/v8/upload-batch/private/$BATCH_PRIVATE_SLUG/file-list"
  METHOD=GET
  VIEW_BATCH_RESPONSE_CODE=$(curl -s \
    -o "$RESPONSE_FILE" \
    -w "%{http_code}" \
    -X $METHOD \
    -H "$AUTH_HEADER" \
    -H "$ACCEPT_HEADER" \
	 	-H "$USER_TOKEN_HEADER" \
    "$VIEW_BATCH_URL")
  VIEW_BATCH_RESPONSE=$(cat "$RESPONSE_FILE" 2> /dev/null)

  print_response_verbose "$METHOD" "$VIEW_BATCH_URL" "" "$VIEW_BATCH_RESPONSE_CODE" "$VIEW_BATCH_RESPONSE"

  if [[ $VIEW_BATCH_RESPONSE_CODE != 200 ]]; then
    echo "Retrieving uploaded files failed" >&2
    handle_interrupt
  fi

  ITEMS=($(parse_from_json "$VIEW_BATCH_RESPONSE" "items[] | .batch_file_id,.file.slug"))
  UPLOADED_SLUGS=()
  for((BFID_INDEX=0;BFID_INDEX < ${#ITEMS[@]};BFID_INDEX+=2)); do
    FILE_SLUG_INDEX=$((BFID_INDEX + 1))
    UPLOADED_SLUGS[${ITEMS[BFID_INDEX]}]=${ITEMS[FILE_SLUG_INDEX]}
  done
fi


FILE_URL_PARTS=()
BATCH_FILE_ID=1
for FILE in "${FILES[@]}"; do
  FILE_NAME=$(basename "$FILE")
  if [[ $IS_RERUN != 1 || ! " ${ITEMS[*]} " =~ " $BATCH_FILE_ID " ]]; then
    echo "Uploading file $BATCH_FILE_ID \"$FILE_NAME\""
    UPLOAD_URL="$UPLOAD_LINK&batch_file_id=$BATCH_FILE_ID"
    UPLOAD_RESPONSE_CODE=$(curl -s \
      -o "$RESPONSE_FILE" \
      -w "%{http_code}" \
      -F "file=@$FILE" \
      "$UPLOAD_URL")
    UPLOAD_RESPONSE=$(cat "$RESPONSE_FILE" 2> /dev/null)

    print_response_verbose "POST" "$UPLOAD_URL" "" "$UPLOAD_RESPONSE_CODE" "$UPLOAD_RESPONSE"

    FILE_SLUG=$(parse_from_json "$UPLOAD_RESPONSE" slug)
    if [[ "$FILE_SLUG" == '' || "$FILE_SLUG" == null ]]; then
      echo "Upload file failed" >&2
      handle_interrupt
    fi
    echo "Upload successful"
  else
    FILE_SLUG=${UPLOADED_SLUGS[$BATCH_FILE_ID]}
  fi

  if [[ $IS_RERUN != 1 ]]; then
    RETRY_COMMAND="$0 --retry-slug=\"$BATCH_PRIVATE_SLUG\"$QUOTED_ARGS"
  fi

	if [[ "$FILE_SLUGS" != "" ]]; then
		FILE_SLUGS="$FILE_SLUGS,"
	fi
	if [[ "$UPLOAD_TOKENS" != "" ]]; then
		UPLOAD_TOKENS="$UPLOAD_TOKENS,"
	fi

  FILE_URL_PARTS+=("$FILE_SLUG/$FILE_NAME")
	FILE_SLUGS="$FILE_SLUGS\"$FILE_SLUG\""
	UPLOAD_TOKENS="$UPLOAD_TOKENS\"$FILE_SLUG\":\"$BATCH_PRIVATE_SLUG:$BATCH_FILE_ID\""
	BATCH_FILE_ID=$((BATCH_FILE_ID + 1))

done


echo "Setting file properties"
if [[ "$FOLDER_SLUG" == "" ]]; then
  USER_DATA_URL="$API_URL/v5/me"
  METHOD=GET
	USER_DATA_RESPONSE_CODE=$(curl -s \
    -o "$RESPONSE_FILE" \
    -w "%{http_code}" \
	 	-X $METHOD \
	 	-H "$AUTH_HEADER" \
	 	-H "$USER_TOKEN_HEADER" \
	 	"$USER_DATA_URL")
  USER_DATA=$(cat "$RESPONSE_FILE" 2> /dev/null)

  print_response_verbose "$METHOD" "$USER_DATA_URL" "" "$USER_DATA_RESPONSE_CODE" "$USER_DATA"

	FOLDER_SLUG=$(parse_from_json "$USER_DATA" user.root_folder_slug)
	if [[ "$FOLDER_SLUG" == '' || "$FOLDER_SLUG" == null ]]; then
		echo "Retrieving root folder failed" >&2
		handle_interrupt
	fi
fi

PROPERTIES_REQUEST="{\"slugs\":[$FILE_SLUGS],\"upload_tokens\":{$UPLOAD_TOKENS},\"folder_slug\":\"$FOLDER_SLUG\"}"
PROPERTIES_URL="$API_URL/v8/file-list/private"
METHOD=PATCH
SET_PROPERTIES_RESPONSE_CODE=$(curl -s \
  -o "$RESPONSE_FILE" \
  -w "%{http_code}" \
	-X $METHOD \
	-H "$AUTH_HEADER" \
	-H "$CONTENT_TYPE_HEADER" \
	-H "$ACCEPT_HEADER" \
	-H "$USER_TOKEN_HEADER" \
	-d "$PROPERTIES_REQUEST" \
	"$PROPERTIES_URL")
SET_PROPERTIES_RESPONSE=$(cat "$RESPONSE_FILE" 2> /dev/null)

print_response_verbose "$METHOD" "$PROPERTIES_URL" "$PROPERTIES_REQUEST" "$SET_PROPERTIES_RESPONSE_CODE" "$SET_PROPERTIES_RESPONSE"

if [[ $SET_PROPERTIES_RESPONSE_CODE != 200 ]]; then
	echo 'Set files properties failed' >&2
	handle_interrupt
fi
echo "File properties set"

echo "Committing files"
COMMIT_BATCH_REQUEST="{\"status\":\"confirmed\",\"owner_login\":\"$LOGIN\"}"
COMMIT_BATCH_URL="$API_URL/v8/upload-batch/private/$BATCH_PRIVATE_SLUG"
METHOD=PATCH
COMMIT_RESPONSE_CODE=$(curl -s \
  -o "$RESPONSE_FILE" \
  -w "%{http_code}" \
	-X $METHOD \
	-H "$AUTH_HEADER" \
	-H "$CONTENT_TYPE_HEADER" \
	-H "$ACCEPT_HEADER" \
	-H "$USER_TOKEN_HEADER" \
	-d "$COMMIT_BATCH_REQUEST" \
	"$COMMIT_BATCH_URL")
COMMIT_RESPONSE=$(cat "$RESPONSE_FILE" 2> /dev/null)

print_response_verbose "$METHOD" "$COMMIT_BATCH_URL" "$COMMIT_BATCH_REQUEST" "$COMMIT_RESPONSE_CODE" "$COMMIT_RESPONSE"

if [[ $COMMIT_RESPONSE_CODE != 200 ]]; then
	echo 'Upload batch commit failed' >&2
	handle_interrupt
fi

echo "Files committed:"
SITE="https://${API_HOST/apis./}/file"
for URL_PART in "${FILE_URL_PARTS[@]}"; do
  echo "$SITE/$URL_PART"
done
