#!/usr/bin/env bash


# Bash unofficial strict mode
set -eo pipefail
IFS=$'\n\t'

cd "$(git rev-parse --show-toplevel)"

USAGE='git-magic [-a] [-m msg] [-e] [-p] [-f]'

ALL=false
PUSH=false
FORCE=''
ARGS=()

while getopts "m:eapfh" arg; do
  case "${arg}" in
    m)
      ARGS+=("-m")
      ARGS+=("${OPTARG}")
      ;;
    e)
      ARGS+=("-e")
      ;;
    a)
      ALL=true
      ;;
    p)
      PUSH=true
      ;;
    f)
      FORCE='--force-with-lease'
      ;;
    h)
      echo "$USAGE"
      exit 0
      ;;
    ?)
      echo "${USAGE}"
      exit 1
      ;;
  esac
done

shift $((OPTIND-1))

if [[ $# != 0 ]]; then
  echo "Unknown arguments: $*"
  echo "${USAGE}"
  exit 1
fi

set -- "${ARGS[@]}" # restore positional parameters

if [[ $ALL == true ]]; then

  # Check if there is no changes to stage
  if [[ -z $(git status --porcelain) ]]; then
    echo "No changes to commit"
    exit 0
  fi

  # Get confirmation from user
  git status
  echo "Everything will be added"
  read -rp "Press enter to continue"

  # Restore staging area so that, for example,
  # add and modify will not be separate entries in status
  git restore --staged . || true
  git add .
fi

# Commit with generated message
git commit --no-edit "$@" -m "$(git status --porcelain -uno)"

if [[ $PUSH == true ]]; then
  git push $FORCE
fi

# --no-edit by default. use option -e to override this

# Arguments are passed with quoted "$@" to avoid misparsing

# Generated message comes after user provided arguments
# so that user can insert title before it
