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

usage() {
  cat <<'USAGE'
Usage:
  ./upload_to_github.sh [options]

Options:
  -m, --message MESSAGE    Commit message. Default: "Update AutoCalib-Workshop"
  -r, --repo-url URL       GitHub repository URL. Uses existing origin if omitted.
  -b, --branch BRANCH      Branch to push. Default: current branch.
      --remote NAME        Git remote name. Default: origin.
      --dry-run            Print commands without changing anything.
  -h, --help               Show this help.

Examples:
  ./upload_to_github.sh -m "Initial upload"
  ./upload_to_github.sh -r https://github.com/USER/REPO.git -m "Upload project"
  GITHUB_REPO_URL=git@github.com:USER/REPO.git ./upload_to_github.sh
USAGE
}

die() {
  echo "Error: $*" >&2
  exit 1
}

run() {
  echo "+ $*"
  if [[ "${DRY_RUN}" != "1" ]]; then
    "$@"
  fi
}

PROJECT_DIR="${PROJECT_DIR:-$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)}"
REMOTE_NAME="${REMOTE_NAME:-origin}"
REPO_URL="${GITHUB_REPO_URL:-}"
BRANCH="${BRANCH:-}"
COMMIT_MESSAGE="${COMMIT_MESSAGE:-Update AutoCalib-Workshop}"
DRY_RUN=0

while [[ $# -gt 0 ]]; do
  case "$1" in
    -m|--message)
      [[ $# -ge 2 ]] || die "missing value for $1"
      COMMIT_MESSAGE="$2"
      shift 2
      ;;
    -r|--repo-url)
      [[ $# -ge 2 ]] || die "missing value for $1"
      REPO_URL="$2"
      shift 2
      ;;
    -b|--branch)
      [[ $# -ge 2 ]] || die "missing value for $1"
      BRANCH="$2"
      shift 2
      ;;
    --remote)
      [[ $# -ge 2 ]] || die "missing value for $1"
      REMOTE_NAME="$2"
      shift 2
      ;;
    --dry-run)
      DRY_RUN=1
      shift
      ;;
    -h|--help)
      usage
      exit 0
      ;;
    *)
      die "unknown option: $1"
      ;;
  esac
done

command -v git >/dev/null 2>&1 || die "git is not installed"
[[ -d "${PROJECT_DIR}" ]] || die "project directory does not exist: ${PROJECT_DIR}"

cd "${PROJECT_DIR}"

if ! git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
  run git init
fi

CURRENT_BRANCH="$(git branch --show-current 2>/dev/null || true)"
if [[ -z "${BRANCH}" ]]; then
  if [[ -n "${CURRENT_BRANCH}" ]]; then
    BRANCH="${CURRENT_BRANCH}"
  elif git rev-parse --verify HEAD >/dev/null 2>&1; then
    die "detached HEAD; provide a branch with -b or BRANCH=..."
  else
    BRANCH="main"
  fi
fi

if [[ -n "${CURRENT_BRANCH}" && "${CURRENT_BRANCH}" != "${BRANCH}" ]]; then
  if git show-ref --verify --quiet "refs/heads/${BRANCH}"; then
    run git switch "${BRANCH}"
  else
    run git switch -c "${BRANCH}"
  fi
fi

if git remote get-url "${REMOTE_NAME}" >/dev/null 2>&1; then
  if [[ -n "${REPO_URL}" ]]; then
    run git remote set-url "${REMOTE_NAME}" "${REPO_URL}"
  fi
else
  [[ -n "${REPO_URL}" ]] || die "remote '${REMOTE_NAME}' does not exist; provide --repo-url URL"
  run git remote add "${REMOTE_NAME}" "${REPO_URL}"
fi

HAS_WORKTREE_CHANGES=0
if ! git diff --quiet || ! git diff --cached --quiet || [[ -n "$(git ls-files --others --exclude-standard)" ]]; then
  HAS_WORKTREE_CHANGES=1
fi

if [[ "${HAS_WORKTREE_CHANGES}" == "1" && "${DRY_RUN}" != "1" ]]; then
  [[ -n "$(git config --get user.name || true)" ]] || die "git user.name is not set"
  [[ -n "$(git config --get user.email || true)" ]] || die "git user.email is not set"
fi

run git add -A

if git diff --cached --quiet; then
  echo "No staged changes to commit."
else
  run git commit -m "${COMMIT_MESSAGE}"
fi

run git push -u "${REMOTE_NAME}" "${BRANCH}"
echo "Done."
