#!/bin/zsh

set -euo pipefail

confirm_action() {
	local prompt="$1"
	local response
	read -r "response?${prompt} (Y/n): "
	case "$response" in
	[Yy] | "")
		return 0
		;;
	*)
		return 1
		;;
	esac
}

show_elpa_files() {
	echo "=== Files to be added to commit ==="
	printf '%s\n' "$1" | while read -r file_status file; do
		case "$file_status" in
		M | MM | AM)
			echo "  modified:   $file"
			;;
		A)
			echo "  new file:   $file"
			;;
		D)
			echo "  deleted:    $file"
			;;
		\?\?)
			echo "  new file:   $file"
			;;
		R*)
			echo "  renamed:    $file"
			;;
		*)
			echo "  $file_status $file"
			;;
		esac
	done
}

readonly elpa_dir='emacs/.emacs.d/elpa'

pushd "$DOTFILES_ROOT" || exit

# The pathspec-scoped commit below is a partial commit, which git refuses while
# a merge or cherry-pick is in progress; abort up front with a clear message
# instead of dying mid-flow at the commit
if git rev-parse -q --verify MERGE_HEAD >/dev/null ||
	git rev-parse -q --verify CHERRY_PICK_HEAD >/dev/null; then
	echo "Cannot commit Emacs package update: merge or cherry-pick in progress; conclude it with git commit && git push"
	popd || exit
	exit 1
fi

# The commits below are scoped to elpa, so staged changes outside it would be
# silently left out of the commit; abort early instead
staged_outside_elpa=$(git diff --cached --name-only -- ":!${elpa_dir}")
readonly staged_outside_elpa
if [ -n "$staged_outside_elpa" ]; then
	echo "Cannot commit Emacs package update: staged changes outside ${elpa_dir}/"
	echo "$staged_outside_elpa"
	popd || exit
	exit 1
fi

# Show current git status
echo "=== Git Status ==="
git status
echo

# Check if there are any .el or .elc files changed. git status --porcelain
# covers staged, unstaged, and untracked changes alike, so elpa content
# pre-staged past the guard above is classified the same as unstaged (the
# previous probes missed them: --diff-filter=MD dropped the R entries rename
# detection produced, and git ls-files --others cannot see staged files).
# Note: .el and .elc files should only exist within package subdirectories, not
# in the top-level elpa directory itself, so **/*.el and **/*.elc are sufficient
elisp_status=$(git status --porcelain --ignore-submodules=dirty -- "${elpa_dir}/**/*.el" "${elpa_dir}/**/*.elc")
readonly elisp_status

# Check for any changed files in the elpa directory
elpa_status=$(git status --porcelain --ignore-submodules=dirty -- "$elpa_dir")
readonly elpa_status

if [ -n "$elisp_status" ]; then
	commit_message="Emacs package update"
elif [ -n "$elpa_status" ]; then
	commit_message="Emacs package metadata update"
else
	echo "Nothing to commit for Emacs package update (no changes found in ${elpa_dir}/)"
	popd || exit
	exit 1
fi
readonly commit_message

show_elpa_files "$elpa_status"
echo
echo "Commit message: \"$commit_message\""
echo

if confirm_action "Proceed with commit and push?"; then
	git add "$elpa_dir"
	git commit -m "$commit_message" -- "$elpa_dir"
	git push
	echo "Successfully committed and pushed changes."
else
	echo "Operation cancelled."
	popd || exit
	exit 1
fi

popd || exit
