#!/usr/bin/env bash
set -euo pipefail

burrow_user="${USER:-${LOGNAME:-runner}}"
export PATH="$PATH:/opt/homebrew/bin:/usr/local/bin:/etc/profiles/per-user/${burrow_user}/bin"

cd "$(dirname "${BASH_SOURCE[0]}")/.."

TAG_PREFIX="builds/"
DEFAULT_VERSION_REMOTE="origin"
if git remote get-url forgejo >/dev/null 2>&1; then
  DEFAULT_VERSION_REMOTE="forgejo"
fi
VERSION_REMOTE="${BURROW_VERSION_REMOTE:-$DEFAULT_VERSION_REMOTE}"
VERSION_REQUIRE_REMOTE="${BURROW_VERSION_REQUIRE_REMOTE:-false}"
COMMAND="${1:-}"

truthy() {
  case "$1" in
    1|true|TRUE|True|yes|YES|Yes|y|Y|on|ON|On) return 0 ;;
    *) return 1 ;;
  esac
}

list_local_build_tags() {
  git tag -l "${TAG_PREFIX}[0-9]*"
}

latest_local_build_tag() {
  list_local_build_tags | sort -n -t'/' -k2 | tail -n 1
}

latest_remote_build_record() {
  local raw rc=0
  raw="$(git ls-remote --tags --refs "$VERSION_REMOTE" "refs/tags/${TAG_PREFIX}[0-9]*" 2>/dev/null)" || rc=$?
  if [[ $rc -ne 0 ]]; then
    return $rc
  fi
  if [[ -z "$raw" ]]; then
    return 0
  fi
  printf '%s\n' "$raw" | awk -F'\t' -v prefix="refs/tags/${TAG_PREFIX}" '
    $2 ~ ("^" prefix "[0-9]+$") {
      build = $2
      sub("^refs/tags/", "", build)
      print build "\t" $1
    }
  ' | sort -n -t'/' -k2 | tail -n 1
}

resolve_build_state() {
  local remote_record local_latest remote_status=0
  BUILD_STATE_SOURCE="local"
  LATEST_BUILD=""
  LATEST_BUILD_COMMIT=""

  remote_record="$(latest_remote_build_record)" || remote_status=$?
  if [[ $remote_status -eq 0 ]]; then
    BUILD_STATE_SOURCE="remote"
    if [[ -n "$remote_record" ]]; then
      LATEST_BUILD="$(printf '%s\n' "$remote_record" | cut -f1)"
      LATEST_BUILD_COMMIT="$(printf '%s\n' "$remote_record" | cut -f2)"
    fi
  else
    if truthy "$VERSION_REQUIRE_REMOTE"; then
      echo "error: unable to resolve authoritative build tags from ${VERSION_REMOTE}" >&2
      exit "$remote_status"
    fi
    echo "warning: unable to resolve authoritative build tags from ${VERSION_REMOTE}; falling back to local tags" >&2
    local_latest="$(latest_local_build_tag)"
    if [[ -n "$local_latest" ]]; then
      LATEST_BUILD="$local_latest"
      LATEST_BUILD_COMMIT="$(git rev-parse -q --verify "refs/tags/${LATEST_BUILD}^{commit}" 2>/dev/null || true)"
    fi
  fi

  if [[ -z "$LATEST_BUILD" ]]; then
    LATEST_BUILD_NUMBER="0"
  else
    LATEST_BUILD_NUMBER="${LATEST_BUILD#$TAG_PREFIX}"
  fi
}

resolve_build_state

HEAD_COMMIT="$(git rev-parse HEAD)"

ANCESTRY_STATE="ok"
if [[ -n "${LATEST_BUILD_NUMBER}" && "${LATEST_BUILD_NUMBER}" != "0" ]]; then
  if [[ -n "${LATEST_BUILD_COMMIT}" ]] && git cat-file -e "${LATEST_BUILD_COMMIT}^{commit}" 2>/dev/null; then
    if ! git merge-base --is-ancestor "${LATEST_BUILD_COMMIT}" HEAD; then
      ANCESTRY_STATE="not-descended"
      if [[ "$COMMAND" != "status" ]]; then
        echo "error: HEAD is not descended from build ${LATEST_BUILD_NUMBER}" >&2
        exit 1
      fi
    fi
  else
    ANCESTRY_STATE="missing-tag-commit"
    echo "notice: skipping build ancestry check (missing ${LATEST_BUILD} commit, likely shallow checkout)" >&2
  fi
fi

BUILD_NUMBER="$LATEST_BUILD_NUMBER"

if [[ "$COMMAND" == "increment" || "$COMMAND" == "pre-increment" ]]; then
  if [[ -n "${BURROW_BUILD_NUMBER_OVERRIDE:-}" ]]; then
    if [[ ! "${BURROW_BUILD_NUMBER_OVERRIDE}" =~ ^[0-9]+$ ]]; then
      echo "error: BURROW_BUILD_NUMBER_OVERRIDE must be an integer" >&2
      exit 1
    fi
    if (( BURROW_BUILD_NUMBER_OVERRIDE <= LATEST_BUILD_NUMBER )); then
      echo "error: BURROW_BUILD_NUMBER_OVERRIDE must be greater than ${LATEST_BUILD_NUMBER}" >&2
      exit 1
    fi
    NEW_BUILD_NUMBER="${BURROW_BUILD_NUMBER_OVERRIDE}"
  else
    NEW_BUILD_NUMBER=$((LATEST_BUILD_NUMBER + 1))
  fi
  NEW_TAG="$TAG_PREFIX$NEW_BUILD_NUMBER"
  BUILD_NUMBER="$NEW_BUILD_NUMBER"
fi

if [[ "$COMMAND" == "increment" ]]; then
  git tag "$NEW_TAG"
  git push --quiet "$VERSION_REMOTE" "$NEW_TAG"
fi

CONFIG_PATH="Apple/Configuration/Version.xcconfig"
if [[ "$COMMAND" != "status" && -f "$CONFIG_PATH" ]]; then
  current_config_version="$(sed -n 's/^[[:space:]]*CURRENT_PROJECT_VERSION[[:space:]]*=[[:space:]]*//p' "$CONFIG_PATH" 2>/dev/null | tail -n 1 || true)"
  if [[ "$current_config_version" != "$BUILD_NUMBER" ]]; then
    echo "CURRENT_PROJECT_VERSION = $BUILD_NUMBER" > "$CONFIG_PATH"
  fi
  git update-index --assume-unchanged "$CONFIG_PATH" 2>/dev/null || true
fi

if [[ "$COMMAND" == "status" ]]; then
  if [[ "${ANCESTRY_STATE}" == "ok" && "${LATEST_BUILD_NUMBER}" != "0" && -n "${LATEST_BUILD_COMMIT}" && "${HEAD_COMMIT}" == "${LATEST_BUILD_COMMIT}" ]]; then
    echo "clean"
  else
    echo "dirty"
  fi
  exit 0
fi

echo "$BUILD_NUMBER"
