#!/bin/bash
## The hand-editing journey: import and verify narrow to named branches,
## and import -f replays over an existing ref, keeping the old tip in the
## reflog.  Without -f, an existing ref is still refused.
set -euo pipefail
cd "$(dirname "$0")"
source ./lib.sh

work=$(mktemp -d)
trap 'rm -rf "$work"' EXIT

make_corpus "$work/corpus"
source "$work/corpus/FACTS"

"$PATCHETTE" export --subject="$work/corpus/dev" --patches="$work/patches" "$base" topic/fancy docs-polish >/dev/null
fancy=$'topic\u00a6fancy'

# --- selection ---
git clone -q "$work/corpus/upstream" "$work/subset"
"$PATCHETTE" import --subject="$work/subset" --patches="$work/patches" docs-polish >/dev/null
EXPECT equal "a named-subset import creates only the named refs" -- \
	"$(git -C "$work/subset" for-each-ref --format='%(refname)' refs/heads/docs-polish refs/heads/topic/fancy)" "refs/heads/docs-polish"
EXPECT refusal "a selection naming no branch folder is an error" "no branch folder for 'no-such-branch'" -- \
	"$PATCHETTE" import --subject="$work/subset" --patches="$work/patches" no-such-branch

# Narrowed verify reads only the named folders: tamper the other one and
# watch selection dodge it while an unnarrowed verify trips on it.
sed -i 's/> Polish the readme/> Polish the readme harder/' "$work/patches/docs-polish/polish-the-readme.patch"
EXPECT success "a narrowed verify reads only the named folders" -- \
	"$PATCHETTE" verify --subject="$work/corpus/dev" --patches="$work/patches" topic/fancy
EXPECT refusal "while an unnarrowed verify still sees the rest" "MISMATCH" -- \
	"$PATCHETTE" verify --subject="$work/corpus/dev" --patches="$work/patches"

# Narrowing narrows validation too: a folder that fails validation (here, an
# orphan patch file) blocks only the commands that include it.
cp -r "$work/patches" "$work/strayed"
cp "$work/strayed/docs-polish/polish-the-readme.patch" "$work/strayed/docs-polish/stray.patch"
EXPECT success "a narrowed verify isn't blocked by another folder's validation failure" -- \
	"$PATCHETTE" verify --subject="$work/corpus/dev" --patches="$work/strayed" topic/fancy
EXPECT refusal "while an unnarrowed verify refuses it" "orphan" -- \
	"$PATCHETTE" verify --subject="$work/corpus/dev" --patches="$work/strayed"

# --- import -f ---
# The docs-polish patch set is now hand-edited; its replay tip differs from
# the branch the earlier import created.
EXPECT refusal "an existing ref is refused without -f, which gets mentioned" "-f updates it instead" -- \
	"$PATCHETTE" import --subject="$work/subset" --patches="$work/patches" docs-polish
EXPECT equal "the refused ref is untouched" -- \
	"$(git -C "$work/subset" rev-parse refs/heads/docs-polish)" "$tip_docs_polish"

"$PATCHETTE" import -f --subject="$work/subset" --patches="$work/patches" docs-polish >/dev/null
newtip=$(git -C "$work/subset" rev-parse refs/heads/docs-polish)
EXPECT success "import -f updates the ref to the edited replay" -- \
	test "$newtip" != "$tip_docs_polish"
EXPECT success "the previous tip remains findable in the reflog" -- \
	grep -q "$tip_docs_polish" <(git -C "$work/subset" log -g --format=%H refs/heads/docs-polish)

# -f still never moves a branch some checkout has checked out (git branch -f
# refuses the same): that checkout's index and files would be left behind,
# reading as a staged revert.  The main checkout and linked worktrees alike.
git clone -q "$work/corpus/upstream" "$work/busy"
git -C "$work/busy" switch -qc docs-polish
EXPECT refusal "import -f refuses a branch checked out in the main checkout" "checked out in" -- \
	"$PATCHETTE" import -f --subject="$work/busy" --patches="$work/patches" docs-polish
EXPECT equal "and leaves it where it was" -- \
	"$(git -C "$work/busy" rev-parse refs/heads/docs-polish)" "$base"
git -C "$work/busy" branch -q topic/fancy main
git -C "$work/busy" worktree add -q "$work/busy-wt" topic/fancy
EXPECT refusal "import -f refuses a branch checked out in a linked worktree" "checked out in" -- \
	"$PATCHETTE" import -f --subject="$work/busy" --patches="$work/patches" topic/fancy
EXPECT equal "and leaves it where it was" -- \
	"$(git -C "$work/busy" rev-parse refs/heads/topic/fancy)" "$base"

# A bare repo has no reflogs by default (core.logAllRefUpdates is off), so
# this leg is what proves import creates the reflog trail itself rather than
# inheriting it from non-bare defaults.
git clone -q --bare "$work/corpus/upstream" "$work/bare.git"
"$PATCHETTE" import --subject="$work/bare.git" --patches="$work/patches" topic/fancy >/dev/null
sed -i 's/> Teach gizmo to hum/> Teach gizmo to really hum/' "$work/patches/$fancy/teach-gizmo-to-hum.patch"
"$PATCHETTE" import -f --subject="$work/bare.git" --patches="$work/patches" topic/fancy >/dev/null
EXPECT success "even in a bare repo, the previous tip remains in the reflog" -- \
	grep -q "$tip_topic_fancy" <(git -C "$work/bare.git" log -g --format=%H refs/heads/topic/fancy)

# Forcing a ref to the tip it already has changes nothing, and says so,
# rather than claiming an update with the same tip as "previous".
EXPECT success "a no-op import -f reports the ref as unchanged" -- \
	bash -c '"$@" | grep -q "unchanged"' -- \
	"$PATCHETTE" import -f --subject="$work/bare.git" --patches="$work/patches" topic/fancy

exit "$RESULT"
