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

LAST_TAG=$(git describe --abbrev=0) || ( echo no annotated tags found on this branch >&2 ; exit 1 )

VERSION=${LAST_TAG#v}
VERSION=${VERSION#V}
IFS='.' read -r MAJOR MINOR PATCH <<< "$VERSION"

COMMIT_LOG_DELIM="===END==="

commits_raw=$(
  git log "${LAST_TAG}"..HEAD --pretty=format:"%s%n%b%n${COMMIT_LOG_DELIM}"
)

if [[ -z "$commits_raw" ]]; then
  echo "no new commits since $LAST_TAG"
  exit 2
fi

has_breaking=false
has_feature=false
has_bugfix=false
commit_subjects=()

commit_text=
while IFS= read -r line; do
  if [[ "$line" == "$COMMIT_LOG_DELIM" ]]; then
    subject=$(printf '%s' "$commit_text" | head -n1)

    # Breaking change/major version
    breaking_change_regex_footer='BREAKING CHANGE:.*$'
    breaking_change_regex_bang='^[[:lower:]]+.*!: .+' # an overly permissive regex with the `.*`, but I was having trouble precisely matching a `(scope)`
    if [[ $(printf '%s' "$commit_text") =~ $breaking_change_regex_footer ]]; then
      has_breaking=true
      subject=$(printf "%s\n  %s" "$subject" "${BASH_REMATCH[0]}")
    elif [[ "$subject" =~ $breaking_change_regex_bang ]]; then
      has_breaking=true
      subject=$(printf "%s\n  BREAKING CHANGE" "$subject")
    fi
    commit_subjects+=("$subject")

    # Feature/minor version
    if printf '%s' "$subject" | grep -qE '^feat.(.+)?:'; then
      has_feature=true
    fi

    # Bugfix/patch version
    if printf '%s' "$subject" | grep -qE '^fix(.+)?:'; then
      has_bugfix=true
    fi

    commit_text=""
  else
    commit_text+="$line"$'\n'
  fi
done <<< "$commits_raw"

if $has_breaking; then
  if [[ "$MAJOR" -eq 0 ]]; then
    ((MINOR++))
    PATCH=0
  else
    ((MAJOR++))
    MINOR=0
    PATCH=0
  fi

elif $has_feature; then
  ((MINOR++))
  PATCH=0

elif $has_bugfix; then
  ((PATCH++))
fi

NEW_TAG="v${MAJOR}.${MINOR}.${PATCH}"

printf '%s\n\n' "$NEW_TAG"
for subj in "${commit_subjects[@]}"; do
  printf -- "- %s\n" "$subj"
done

if [[ "$LAST_TAG" = "$NEW_TAG" ]]; then
  echo "===END===" >&2
  echo no breaking changes, features, or bugfixes. >&2
  exit 3
fi
