#!/usr/bin/env bash
# reset environment variables that could interfere with normal usage
unset -v GREP_OPTIONS
# put all utility functions here

# make a temporary file
git_extra_mktemp() {
    mktemp -t "$(basename "$0")".XXXXXXX
}

git_extra_default_branch() {
    local extras_default_branch init_default_branch
    extras_default_branch=$(git config --get git-extras.default-branch)
    init_default_branch=$(git config --get init.defaultBranch)
    if [ -n "$extras_default_branch" ]; then
        echo "$extras_default_branch"
    elif [ -n "$init_default_branch" ]; then
        echo "$init_default_branch"
    else
        echo "main"
    fi
}
#
# check whether current directory is inside a git repository
#

is_git_repo() {
  git rev-parse --show-toplevel > /dev/null 2>&1
  result=$?
  if test $result != 0; then
    >&2 echo 'Not a git repo!'
    exit $result
  fi
}

is_git_repo

function _usage()
{
  local command="git sync"
  cat << EOS
Usage:
  ${command} [<remote> <branch>]
  ${command} -h | --help
  ${command} -s | --soft
  ${command} -f | --force

Sync local branch with <remote>/<branch>.
When <remote> and <branch> are not specified on the command line, upstream of local branch will be used by default.
All changes and untracked files and directories will be removed unless you add -s(--soft).

Examples:
  Sync with upstream of local branch:
    ${command}

  Sync with origin/master:
    ${command} origin master

  Sync without cleaning untracked files:
    ${command} -s

  Sync without interaction:
    ${command} -f
EOS
}

function main()
{
  while [ "$1" != "" ]; do
    case $1 in
      -h | --help)
        _usage
        exit
        ;;
      -s | --soft)
        local soft="true"
        ;;
      -f | --force)
        local force="YES"
        ;;
      * )
        if [ "${remote}" = "" ]; then
          local remote="$1"
        elif [ "${branch}" = "" ]; then
          local branch="$1"
        else
          echo -e "Error: too many arguments.\n"
          _usage
          exit 1
        fi
        ;;
    esac
    shift
  done

  local remote_branch
  if [ -z "${remote}" ]; then
    if ! remote_branch="$(git rev-parse --abbrev-ref --symbolic-full-name '@{u}' 2>/dev/null)"; then
      echo "There is no upstream information of local branch."
      exit 1
    fi
    local branch="$(git rev-parse --abbrev-ref --symbolic-full-name @)"
    local remote=$(git config "branch.${branch}.remote")
  elif [ -z "${branch}" ]; then
    echo -e "Error: too few arguments.\n"
    _usage
    exit 1
  else
    remote_branch="${remote}/${branch}"
  fi

  if [ "${force}" != "YES" ]; then
    if [ "${soft}" = "true" ]; then
      echo -n "Are you sure you want to sync with '${remote_branch}'? [y/N]: "
    else
      echo -n "Are you sure you want to clean all changes & sync with '${remote_branch}'? [y/N]: "
    fi
    local force
    read -r force
  fi
  case "${force}" in
    "Y" | "y" | "yes" | "Yes" | "YES" )
      if [ "${soft}" = "true" ]; then
        git fetch "${remote}" "${branch}" && git reset --hard "${remote_branch}"
      else
        git fetch "${remote}" "${branch}" && git reset --hard "${remote_branch}" && git clean -d -f -x
      fi
      ;;
    * )
      echo "Canceled."
      ;;
  esac
}

main "$@"

