#!/bin/sh

set -e

lower() {
	echo "$1" | tr '[:upper:]' '[:lower:]'
}

upper() {
	echo "$1" | tr '[:lower:]' '[:upper:]'
}

# global
MC_TYPE="$(lower "${MC_TYPE:-vanilla}")"
MC_VERSION="$(lower "${MC_VERSION:-latest}")"

# papermc
PAPERMC_BUILD="$(lower "${PAPERMC_BUILD:-latest}")"

# fabric
FABRIC_LOADER="$(lower "${FABRIC_LOADER:-latest}")"
FABRIC_INSTALLER="$(lower "${FABRIC_INSTALLER:-latest}")"

# other
QUIET=1

req() {
	res=$(curl --fail --silent "$1")
	code=$?

	if [ $code -ne 0 ]; then
		echo "null";
	else
		echo "$res";
	fi
}

error() {
	printf '\x1b[31m[ERROR]\t\x1b[0m%s\n' "$*" > /dev/stderr
	exit 1;
}

log() {
	if [ "$QUIET" -eq 0 ]; then
		printf '\x1b[0m[LOG]\t%s\n' "$*" > /dev/stderr
	fi
}

index_array() {
	array="$1"
	key="$2"
	type="$3"

	if [ "$key" = "latest" ]; then
		index=$(echo "$array" | jq ". | index( last )");
	else
		index=$(echo "$array" | jq ". | index( \"$key\" )");
	fi

	if [ "$index" = "null" ]; then
		error "Invalid $type: $key"
	else
		echo "$array" | jq -r ".[$index]";
	fi
}

#https://api.papermc.io/v2/projects/velocity/versions/3.3.0-SNAPSHOT/

papermc() {
	api="https://api.papermc.io/v2/projects"

	log "Using papermc api v2"

	get_version() {
		log "Getting VERSION for '$MC_TYPE'"
		versions=$(req "$api/$MC_TYPE" | jq -r '.versions')
		if [ "$versions" = "null" ]; then
			error "Invalid TYPE: $MC_TYPE (no versions)"
		fi
		MC_VERSION=$(index_array "$versions" "$MC_VERSION" "VERSION")
		log "VERSION: $MC_VERSION"
	}

	get_build() {
		log "Getting BUILD for '$MC_TYPE@$MC_VERSION'"
		builds=$(req "$api/$MC_TYPE/versions/$MC_VERSION" | jq -r ".builds")
		if [ "$builds" = "null" ]; then
			error "Invalid VERSION: $MC_TYPE@$MC_TYPE (no builds)"
		fi
		PAPERMC_BUILD=$(index_array "$builds" "$PAPERMC_BUILD" "BUILD")
		log "BUILD: $PAPERMC_BUILD"
	}

	get_version
	get_build

	echo "$api/$MC_TYPE/versions/$MC_VERSION/builds/$PAPERMC_BUILD/downloads/$MC_TYPE-$MC_VERSION-$PAPERMC_BUILD.jar"
}

fabric() {
	api="https://meta.fabricmc.net/v2/versions"

	log "Using fabric api v2"

	get_fabric_impl() {
		type="$1"
		value="$2"
		res=""
		if [ "$value" = "latest" ]; then
			res=$(req "$api/$type" | jq -r 'map(select(.stable == true) | .version) | reverse')
		else
			res=$(req "$api/$type" | jq -r 'map(.version) | reverse')
		fi;
		echo $res;
	}

	get_game() {
		log "Getting VERSION for '$MC_TYPE'"
		games=$(get_fabric_impl "game" "$MC_VERSION")
		MC_VERSION=$(index_array "$games" "$MC_VERSION" "VERSION")
		log "VERSION: $MC_VERSION"
	}

	get_loader() {
		log "Getting LOADER for '$MC_TYPE'"
		loaders=$(get_fabric_impl "loader" "$FABRIC_LOADER")
		FABRIC_LOADER=$(index_array "$loaders" "$FABRIC_LOADER" "LOADER")
		log "LOADER: $FABRIC_LOADER"
	}

	get_installer() {
		log "Getting INSTALLER for '$MC_TYPE'"
		installers=$(get_fabric_impl "installer" "$FABRIC_INSTALLER")
		FABRIC_INSTALLER=$(index_array "$installers" "$FABRIC_INSTALLER" "INSTALLER")
		log "INSTALLER: $FABRIC_INSTALLER"
	}

	get_game
	get_loader
	get_installer

	echo "$api/loader/$MC_VERSION/$FABRIC_LOADER/$FABRIC_INSTALLER/server/jar"
}

vanilla() {
	versions=$(req 'https://launchermeta.mojang.com/mc/game/version_manifest.json' | jq '.versions | map({ "id": .id, "type": .type, "url": .url }) | reverse');

	map_type_impl() {
		type="$1"
		echo "$versions" | jq -r "map(select(.type == \"$type\"))"
	}

	get_version() {
		log "Getting VERSION for '$MC_TYPE'"
		version=""
		case "$MC_VERSION" in
			"latest")
				version=$(map_type_impl "release" | jq -r 'last')
				;;
			"snapshot")
				version=$(map_type_impl "snapshot" | jq -r 'last')
				;;
			*)
				version=$(echo "$versions" | jq ".[] | select(.id == \"$MC_VERSION\")")
				;;
		esac

		if [ "$version" = "null" ] || [ "$version" = "" ]; then
			error "Invalid VERSION: $MC_VERSION"
		fi

		log "VERSION: $(echo "$version" | jq -r '.id')"

		json=$(echo "$version" | jq -r '.url')
		url=$(req "$json" | jq -r '.downloads.server.url')

		if [ "$url" = "null" ]; then
			error "Cannot get server jar for VERSION: $MC_VERSION"
		fi

		echo "$url"
	}

	get_version
}

get_url() {

	log "TYPE: $MC_TYPE"

	case "$MC_TYPE" in
		"vanilla")
			vanilla
			;;
		"paper" | "waterfall" | "velocity" | "folia")
			papermc
			;;
		"fabric")
			fabric
			;;
		*)
			error "Invalid TYPE: $MC_TYPE"
			;;
	esac
}

usage() {
	printf "usage: mcjar [options]\n"
}

help() {
	printf "usage: mcjar [options]\n\n"
	printf "options:\n"
	printf "\t-h\tshow this message\n"
	printf "\t-l\tshow logging (verbose)\n\n"

	printf "\t-t TYPE\t\tset the mc server type\n"
	printf "\t  [vanilla,fabric,paper,folia,velocity,waterfall]\n\n"
	printf "\t-v VERSION\tset the mc server version\n"
	printf "\t  [latest,snapshot,<version>]\n\n"

	printf "environment:\n"
	printf "\tMC_TYPE\t\tsets the mc server type (same as -t TYPE)\n"
	printf "\tMC_VERSION\tsets the mc server version (same as -v VERSION)\n\n"

	printf "\tPAPERMC_BUILD\tsets the papermc build\n\n"

	printf "\tFABRIC_LOADER\t\tsets the fabric loder version\n"
	printf "\tFABRIC_INSTALLER\tsets the fabric installer version\n\n"
}


while getopts "hlt:v:" arg > /dev/null; do
	case $arg in
		h)
			help
			exit 0
			;;
		l)
			QUIET=0
			;;
		t)
			MC_TYPE=${OPTARG}
			;;
		v)
			MC_VERSION=${OPTARG}
			;;
		?)
			error "unknown option"
			exit 1
			;;
	esac;
done;

get_url