#!/bin/bash
# Aparc Mac launcher. Checks the public play feed, updates the climb into
# ~/Library/Application Support/Aparc/game, then opens Aparc.app.
set -euo pipefail

FEED="${APARC_PLAY_URL:-https://aparc.thomaswt.dk/play/latest.json}"
SUPPORT="${HOME}/Library/Application Support/Aparc"
GAME_DIR="${SUPPORT}/game"
APP="${GAME_DIR}/Aparc.app"
VERSION_FILE="${SUPPORT}/version.txt"
ZIP="${SUPPORT}/_update.zip"
STAGING="${SUPPORT}/_update"

die() {
	osascript -e "display dialog \"$1\" with title \"Aparc\" buttons {\"OK\"} default button 1" >/dev/null 2>&1 || true
	exit 1
}

note() {
	osascript -e "display notification \"$1\" with title \"Aparc\"" >/dev/null 2>&1 || true
}

json_field() {
	JSON_FILE="$1" JSON_KEY="$2" osascript -l JavaScript -e '
ObjC.import("Foundation");
function js(v) { return ObjC.unwrap(v); }
const env = $.NSProcessInfo.processInfo.environment;
const file = js(env.objectForKey("JSON_FILE"));
const key = js(env.objectForKey("JSON_KEY"));
const raw = $.NSString.stringWithContentsOfFileEncodingError(file, $.NSUTF8StringEncoding, null);
const text = js(raw);
if (!text) { ""; }
else {
  let v = JSON.parse(text);
  key.split(".").forEach((k) => { v = (v == null) ? null : v[k]; });
  (v == null) ? "" : String(v);
}
'
}

resolve_url() {
	local rel="$1"
	if [[ "$rel" == http://* || "$rel" == https://* ]]; then
		printf '%s\n' "$rel"
		return
	fi
	if [[ "$rel" == /* ]]; then
		local host
		host="$(printf '%s' "$FEED" | sed -E 's|(https?://[^/]+).*|\1|')"
		printf '%s%s\n' "$host" "$rel"
		return
	fi
	printf '%s/%s\n' "$(dirname "$FEED")" "$rel"
}

installed_version() {
	if [[ -f "$VERSION_FILE" ]]; then
		tr -d '[:space:]' < "$VERSION_FILE"
	fi
}

game_running() {
	pgrep -f "${GAME_DIR}/Aparc.app/Contents/MacOS/" >/dev/null 2>&1
}

find_app() {
	local root="$1"
	if [[ -d "${root}/Aparc.app" ]]; then
		printf '%s\n' "${root}/Aparc.app"
		return
	fi
	find "$root" -maxdepth 3 -type d -name 'Aparc.app' 2>/dev/null | head -n1 || true
}

install_build() {
	local ver="$1" url="$2" want_sha="$3"
	if game_running; then
		die "Close Aparc before updating, then open the launcher again."
	fi
	note "Hauling ${ver}…"
	mkdir -p "$SUPPORT"
	rm -f "$ZIP"
	curl -fL --retry 3 --retry-delay 2 -o "$ZIP" "$url" || die "Download failed."
	local size
	size="$(wc -c < "$ZIP" | tr -d ' ')"
	if [[ "${size:-0}" -lt 1000000 ]]; then
		die "Download was too small to be the climb."
	fi
	if [[ -n "$want_sha" ]]; then
		local got
		got="$(shasum -a 256 "$ZIP" | awk '{print $1}')"
		if [[ "$got" != "$want_sha" ]]; then
			die "Download checksum mismatch."
		fi
	fi
	rm -rf "$STAGING"
	mkdir -p "$STAGING"
	ditto -x -k "$ZIP" "$STAGING" 2>/dev/null || unzip -q -o "$ZIP" -d "$STAGING"
	local payload
	payload="$(find_app "$STAGING")"
	if [[ -z "$payload" || ! -d "$payload" ]]; then
		die "Zip did not contain Aparc.app."
	fi
	chmod -R u+w "$GAME_DIR" 2>/dev/null || true
	rm -rf "$GAME_DIR"
	mkdir -p "$GAME_DIR"
	ditto "$payload" "$APP"
	chmod +x "$APP/Contents/MacOS/"* 2>/dev/null || true
	xattr -cr "$APP" 2>/dev/null || true
	printf '%s\n' "$ver" > "$VERSION_FILE"
	rm -f "$ZIP"
	rm -rf "$STAGING"
}

start_game() {
	if [[ ! -d "$APP" ]]; then
		die "Aparc.app is missing. Delete version.txt in Application Support/Aparc and open the launcher again."
	fi
	if game_running; then
		note "The gate is already open."
		open "$APP"
		exit 0
	fi
	note "Opening the gate…"
	xattr -cr "$APP" 2>/dev/null || true
	open "$APP"
}

mkdir -p "$SUPPORT"
TMP="$(mktemp -t aparc-feed)"
trap 'rm -f "$TMP"' EXIT

if ! curl -fsSL --retry 3 --retry-delay 1 "$FEED" -o "$TMP"; then
	if [[ -d "$APP" ]]; then
		note "The tower is silent. Starting the installed climb."
		start_game
		exit 0
	fi
	die "Could not reach the update feed."
fi

VER="$(json_field "$TMP" "version" | tr -d '[:space:]')"
REL="$(json_field "$TMP" "macos.url")"
SHA="$(json_field "$TMP" "macos.sha256" | tr -d '[:space:]' | tr '[:upper:]' '[:lower:]')"
if [[ -z "$VER" || -z "$REL" ]]; then
	if [[ -d "$APP" ]]; then
		note "No Mac climb on the feed. Starting the installed build."
		start_game
		exit 0
	fi
	die "Update feed has no macOS build yet."
fi

URL="$(resolve_url "$REL")"
HAVE="$(installed_version)"
if [[ ! -d "$APP" || -z "$HAVE" || "$HAVE" != "$VER" ]]; then
	install_build "$VER" "$URL" "$SHA"
fi
start_game
