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

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"

LOCK_FILE="${REPO_ROOT}/third_party/kvproto.lock"
DEST_DIR="$(cd "${REPO_ROOT}/.." && pwd)/kvproto"
REPO=""
COMMIT=""

usage() {
  cat <<'EOF'
Usage:
  fetch-kvproto.sh [--lock-file PATH] [--dest PATH] [--repo URL] [--commit SHA]

Options:
  --lock-file      Lock file with repo=... and commit=... entries.
  --dest           Destination directory for kvproto checkout.
  --repo           Override repo URL from lock file.
  --commit         Override commit SHA from lock file.
  -h, --help       Show this help message.
EOF
}

read_lock_value() {
  local key="$1"
  sed -n "s/^${key}=//p" "${LOCK_FILE}" | head -n1
}

while [[ $# -gt 0 ]]; do
  case "$1" in
    --lock-file)
      LOCK_FILE="$2"
      shift 2
      ;;
    --dest)
      DEST_DIR="$2"
      shift 2
      ;;
    --repo)
      REPO="$2"
      shift 2
      ;;
    --commit)
      COMMIT="$2"
      shift 2
      ;;
    -h|--help)
      usage
      exit 0
      ;;
    *)
      echo "unknown argument: $1" >&2
      usage >&2
      exit 1
      ;;
  esac
done

if [[ ! -f "${LOCK_FILE}" ]]; then
  echo "lock file not found: ${LOCK_FILE}" >&2
  exit 1
fi

if [[ -z "${REPO}" ]]; then
  REPO="$(read_lock_value repo)"
fi
if [[ -z "${COMMIT}" ]]; then
  COMMIT="$(read_lock_value commit)"
fi

if [[ -z "${REPO}" || -z "${COMMIT}" ]]; then
  echo "invalid lock file (${LOCK_FILE}): expected repo=... and commit=..." >&2
  exit 1
fi

if [[ ! "${COMMIT}" =~ ^[0-9a-f]{40}$ ]]; then
  echo "invalid commit (${COMMIT}): expected a 40-char lowercase hex SHA" >&2
  exit 1
fi

mkdir -p "$(dirname "${DEST_DIR}")"

if [[ -e "${DEST_DIR}" && ! -d "${DEST_DIR}" ]]; then
  echo "destination exists but is not a directory: ${DEST_DIR}" >&2
  exit 1
fi

if [[ -d "${DEST_DIR}/.git" ]]; then
  git -C "${DEST_DIR}" remote set-url origin "${REPO}"
else
  if [[ -d "${DEST_DIR}" ]] && [[ -n "$(ls -A "${DEST_DIR}")" ]]; then
    echo "destination exists and is not an empty git repo: ${DEST_DIR}" >&2
    exit 1
  fi
  rm -rf "${DEST_DIR}"
  git clone --no-checkout "${REPO}" "${DEST_DIR}"
fi

if ! git -C "${DEST_DIR}" fetch --depth=1 origin "${COMMIT}"; then
  git -C "${DEST_DIR}" fetch origin
fi

git -C "${DEST_DIR}" checkout --detach "${COMMIT}"
ACTUAL_COMMIT="$(git -C "${DEST_DIR}" rev-parse HEAD)"
if [[ "${ACTUAL_COMMIT}" != "${COMMIT}" ]]; then
  echo "fetched commit mismatch: expected ${COMMIT}, got ${ACTUAL_COMMIT}" >&2
  exit 1
fi

printf 'repo=%s\n' "${REPO}"
printf 'commit=%s\n' "${COMMIT}"
printf 'dest=%s\n' "${DEST_DIR}"
