#!/usr/bin/env bash

PACKAGE_HOOKS="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"

# Импортируем утилиты для настройки TTY
if [ -f "${PACKAGE_HOOKS}/setup_tty.sh" ]; then
  # shellcheck disable=SC1091
  . "${PACKAGE_HOOKS}/setup_tty.sh"
  # Настраиваем TTY для интерактивного ввода
  setup_tty
fi

# Опциональный параметр - хеш коммита для обновления (если не указан, обновляем HEAD)
TARGET_COMMIT="${1:-HEAD}"

clear_stale_merge_state() {
  local git_dir="$1"
  rm -f "${git_dir}/MERGE_HEAD" \
        "${git_dir}/MERGE_MSG" \
        "${git_dir}/MERGE_MODE" \
        "${git_dir}/MERGE_RR" \
        "${git_dir}/AUTO_MERGE" 2>/dev/null
}

# release_type: major | minor | patch
format_release_message() {
  local release_type="$1"
  local commit_message="$2"

  if echo "$commit_message" | grep -qE "^${release_type}(\([^)]+\))?:"; then
    printf '%s\n' "$commit_message"
    return 0
  fi

  if [ -n "$RELEASE_BRANCH" ] || echo "$commit_message" | grep -qE '^Merge '; then
    local subject
    subject=$(printf '%s' "$commit_message" | head -n 1)
    printf '%s(other): %s\n' "$release_type" "$subject"
    return 0
  fi

  if echo "$commit_message" | grep -qE '^[^:]+:'; then
    local before_colon after_colon
    before_colon=$(echo "$commit_message" | sed 's/:.*$//')
    after_colon=$(echo "$commit_message" | sed 's/^[^:]*: *//')
    printf '%s(%s): %s\n' "$release_type" "$before_colon" "$after_colon"
    return 0
  fi

  printf '%s(other): %s\n' "$release_type" "$commit_message"
}

update_message() {
  local release_type="$1"
  local commit_message
  local git_dir
  local new_message

  commit_message=$(git log --format=%B -n 1 "$TARGET_COMMIT" 2>/dev/null) || return 1
  [ -z "$commit_message" ] && return 1

  if echo "$commit_message" | grep -qE "^${release_type}(\([^)]+\))?:"; then
    return 0
  fi

  git_dir=$(git rev-parse --git-dir 2>/dev/null) || return 1
  new_message=$(format_release_message "$release_type" "$commit_message") || return 1

  # Если обновляем не HEAD, используем rebase
  if [ "$TARGET_COMMIT" != "HEAD" ]; then
    # Проверяем, не находится ли репозиторий в процессе rebase (не проверяем MERGE_HEAD, т.к. в post-merge merge уже завершен)
    if [ -f "${git_dir}/rebase-merge" ] || [ -f "${git_dir}/rebase-apply" ]; then
      echo "Error: Repository is in the middle of a rebase. Cannot update commit message."
      return 1
    fi

    local commit_hash parent temp_sequence_script temp_editor_script message_file short_hash

    commit_hash=$(git rev-parse "$TARGET_COMMIT" 2>/dev/null) || return 1
    parent=$(git rev-parse "${commit_hash}^" 2>/dev/null) || return 1

    message_file=$(mktemp)
    printf '%s' "$new_message" > "$message_file"

    temp_sequence_script=$(mktemp)
    # Используем полный хеш для надежности
    short_hash=$(git rev-parse --short "$commit_hash" 2>/dev/null || echo "${commit_hash:0:7}")
    echo "sed -i.bak '1s/^pick ${short_hash}/reword ${short_hash}/'" > "$temp_sequence_script"
    chmod +x "$temp_sequence_script"

    # Создаем временный скрипт для редактирования сообщения коммита
    temp_editor_script=$(mktemp)
    cat > "$temp_editor_script" <<EOF
#!/usr/bin/env bash
# GIT_EDITOR получает путь к файлу с сообщением коммита как аргумент
cp "$message_file" "\$1"
EOF
    chmod +x "$temp_editor_script"

    export GIT_SEQUENCE_EDITOR="$temp_sequence_script"
    export GIT_EDITOR="$temp_editor_script"

    if ! GIT_WORKFLOW=1 git rebase -i "$parent" >/dev/null 2>&1; then
      git rebase --abort >/dev/null 2>&1
      rm -f "$temp_sequence_script" "$temp_editor_script" "$message_file"
      return 1
    fi

    rm -f "$temp_sequence_script" "$temp_editor_script" "$message_file"
    return 0
  fi

  if [ -f "${git_dir}/rebase-merge" ] || [ -f "${git_dir}/rebase-apply" ]; then
    return 1
  fi

  # post-merge: merge-коммит уже создан, MERGE_HEAD ещё не удалён git'ом
  if [ -n "$RELEASE_BRANCH" ] && [ -f "${git_dir}/MERGE_HEAD" ]; then
    clear_stale_merge_state "$git_dir"
  elif [ -f "${git_dir}/MERGE_HEAD" ]; then
    return 1
  fi

  git rev-parse --verify HEAD >/dev/null 2>&1 || return 1

  git diff --cached --quiet 2>&1 || git reset HEAD >/dev/null 2>&1

  if ! GIT_EDITOR=true GIT_WORKFLOW=1 git commit --amend --no-verify -m "$new_message" >/dev/null 2>&1; then
    echo "Error: Could not amend commit"
    return 1
  fi

  return 0
}

PS3='Select release type: '

MAJOR='⭐️ MAJOR version when you make incompatible API changes'
MINOR='🐞 MINOR version when you add functionality in a backwards compatible manner'
PATCH='✅ PATCH version when you make backwards compatible bug fixes'
CANCEL='Cancel'

options=("${MAJOR}" "${MINOR}" "${PATCH}" "${CANCEL}")
select opt in "${options[@]}"
do
  case $opt in
    $MAJOR)
      update_message 'major' && exit 0 || exit 1
      ;;
    $MINOR)
      update_message 'minor' && exit 0 || exit 1
      ;;
    $PATCH)
      update_message 'patch' && exit 0 || exit 1
      ;;
    $CANCEL)
      exit 1
      ;;
    *) echo "invalid option $REPLY";;
  esac
done
