#!/usr/bin/env bash
# Regression tests for od-wip: list merges origin wip/* refs, local
# refs/system-monitor/worktree-archive/* refs, and vault entries; restore
# reproduces tracked + untracked + secret files byte-identical and refuses a
# duplicate restore of the same salvaged item.
set -uo pipefail
export LC_ALL=C

ROOT="$(cd "$(dirname "$0")/.." && pwd)"
CLI="$ROOT/bin/od-wip"
PASS=0
FAIL=0
TMP="$(mktemp -d "${TMPDIR:-/tmp}/od-wip-test.XXXXXX")"
trap 'rm -rf "$TMP"' EXIT

ok()  { PASS=$((PASS + 1)); printf 'PASS %s\n' "$1"; }
bad() { FAIL=$((FAIL + 1)); printf 'FAIL %s\n     %s\n' "$1" "$2"; }

json_field() {
  local field="$1" json="$2"
  python3 - "$field" "$json" <<'PY'
import json
import sys
obj = json.loads(sys.argv[2])
value = obj
for part in sys.argv[1].split('.'):
    value = value[part]
if isinstance(value, (dict, list)):
    print(json.dumps(value, sort_keys=True))
else:
    print(value)
PY
}

git_q() { git "$@" >/dev/null 2>&1; }

REMOTE="$TMP/origin.git"
REPO="$TMP/repo"
VAULT="$TMP/vault"
mkdir -p "$VAULT"

git init -q --bare "$REMOTE"
git init -q "$REPO"
git -C "$REPO" config user.email t@t
git -C "$REPO" config user.name t
git -C "$REPO" config commit.gpgsign false
git -C "$REPO" remote add origin "$REMOTE"
printf 'hello\n' >"$REPO/tracked.txt"
git -C "$REPO" add -A
git -C "$REPO" commit -qm init
git -C "$REPO" push -q origin HEAD:refs/heads/main
git -C "$REPO" symbolic-ref refs/remotes/origin/HEAD refs/remotes/origin/main 2>/dev/null || true

# --- Fixture 1: a salvaged commit with tracked + untracked + secret files,
# pushed as a wip/* ref, its commit kept reachable via a local archive ref,
# and a matching vault entry holding the untracked/secret delta.
mkdir -p "$REPO/.worktrees/wt-foo"
git -C "$REPO" worktree add -q -b wt/foo "$REPO/.worktrees/wt-foo" HEAD >/dev/null 2>&1
WT="$REPO/.worktrees/wt-foo"
printf 'modified tracked\n' >"$WT/tracked.txt"
printf 'plain untracked\n' >"$WT/notes.txt"
mkdir -p "$WT/.secretdir"
printf 'super secret token\n' >"$WT/.env"
chmod 600 "$WT/.env"

# Build the salvage commit through a temp index, exactly as salvage_push does:
# HEAD tree + all worktree changes, minus nothing (no PRECIOUS_IGNORED_GLOBS
# match here — .env is dropped from the temp index the same way the real
# salvager drops secrets, so the pushed tree excludes it).
TMPIDX="$TMP/salvage.index"
rm -f "$TMPIDX"
GIT_INDEX_FILE="$TMPIDX" git -C "$WT" read-tree HEAD
GIT_INDEX_FILE="$TMPIDX" git -C "$WT" add -A
GIT_INDEX_FILE="$TMPIDX" git -C "$WT" reset -q -- .env 2>/dev/null || true
HEAD_SHA=$(GIT_INDEX_FILE="$TMPIDX" GIT_AUTHOR_NAME="worktree-gc" GIT_AUTHOR_EMAIL="worktree-gc@overdeck.local" \
  GIT_COMMITTER_NAME="worktree-gc" GIT_COMMITTER_EMAIL="worktree-gc@overdeck.local" \
  git -C "$WT" commit-tree -p HEAD -m "salvage: auto-commit idle worktree wt/foo" \
  $(GIT_INDEX_FILE="$TMPIDX" git -C "$WT" write-tree))
SHA7="${HEAD_SHA:0:7}"
WIP_REF="wip/foo-20260801-${SHA7}"
git -C "$WT" push -q origin "${HEAD_SHA}:refs/heads/${WIP_REF}"
git -C "$REPO" update-ref "refs/system-monitor/worktree-archive/${HEAD_SHA}" "$HEAD_SHA"

# The delta archive: everything git status --ignored reports minus the
# reproducible dirs, i.e. notes.txt, .secretdir/, .env here.
DELTA_TAR="$TMP/delta.tar.zst"
tar --zstd -C "$WT" -cf "$DELTA_TAR" notes.txt .secretdir .env
DELTA_SHA=$(sha256sum "$DELTA_TAR" | awk '{print $1}')
DELTA_BYTES=$(stat -c%s "$DELTA_TAR")

ENTRY="repo--wt-foo--20260801-120000--${SHA7}"
ENTRY_DIR="$VAULT/$ENTRY"
mkdir -m 0700 -p "$ENTRY_DIR"
cp "$DELTA_TAR" "$ENTRY_DIR/delta.tar.zst"
chmod 600 "$ENTRY_DIR/delta.tar.zst"
REPO_ABS="$(cd "$REPO" && pwd)"
cat >"$ENTRY_DIR/manifest.json" <<JSON
{
  "repo": "$REPO_ABS",
  "worktree": "$WT",
  "branch": "wt/foo",
  "detached_sha": null,
  "timestamp": "2026-08-01T12:00:00Z",
  "head_sha": "$HEAD_SHA",
  "archive_sha256": "$DELTA_SHA",
  "archive_bytes": $DELTA_BYTES,
  "wip_ref": "$WIP_REF",
  "restore_command": "od-wip restore $ENTRY --repo $REPO_ABS"
}
JSON

git -C "$REPO" worktree remove --force "$WT" >/dev/null 2>&1

# --- Fixture 2: archive-only vault entry (no wip ref) — detached HEAD case.
mkdir -p "$REPO/.worktrees/wt-bar"
git -C "$REPO" worktree add -q --detach "$REPO/.worktrees/wt-bar" HEAD >/dev/null 2>&1
WT2="$REPO/.worktrees/wt-bar"
printf 'bar secret\n' >"$WT2/.env"
TMPIDX2="$TMP/salvage2.index"
rm -f "$TMPIDX2"
GIT_INDEX_FILE="$TMPIDX2" git -C "$WT2" read-tree HEAD
HEAD_SHA2=$(git -C "$WT2" rev-parse HEAD)
SHA7_2="${HEAD_SHA2:0:7}"
git -C "$REPO" update-ref "refs/system-monitor/worktree-archive/${HEAD_SHA2}" "$HEAD_SHA2"
DELTA_TAR2="$TMP/delta2.tar.zst"
tar --zstd -C "$WT2" -cf "$DELTA_TAR2" .env
DELTA_SHA2=$(sha256sum "$DELTA_TAR2" | awk '{print $1}')
DELTA_BYTES2=$(stat -c%s "$DELTA_TAR2")
ENTRY2="repo--detached--20260802-090000--${SHA7_2}"
ENTRY2_DIR="$VAULT/$ENTRY2"
mkdir -m 0700 -p "$ENTRY2_DIR"
cp "$DELTA_TAR2" "$ENTRY2_DIR/delta.tar.zst"
chmod 600 "$ENTRY2_DIR/delta.tar.zst"
cat >"$ENTRY2_DIR/manifest.json" <<JSON
{
  "repo": "$REPO_ABS",
  "worktree": "$WT2",
  "branch": null,
  "detached_sha": "$HEAD_SHA2",
  "timestamp": "2026-08-02T09:00:00Z",
  "head_sha": "$HEAD_SHA2",
  "archive_sha256": "$DELTA_SHA2",
  "archive_bytes": $DELTA_BYTES2,
  "wip_ref": null,
  "restore_command": "od-wip restore $ENTRY2 --repo $REPO_ABS"
}
JSON
git -C "$REPO" worktree remove --force "$WT2" >/dev/null 2>&1

# ---------------------------------------------------------------------------
# list: merges the three sources
# ---------------------------------------------------------------------------

out=$(python3 "$CLI" --vault-root "$VAULT" list --repo "$REPO_ABS" --json 2>"$TMP/err")
rc=$?
if [[ $rc -eq 0 ]]; then ok "list exits 0"; else bad "list exits 0" "rc=$rc err=$(cat "$TMP/err")"; fi

count=$(printf '%s' "$out" | python3 -c 'import json,sys; print(len(json.load(sys.stdin)))' 2>/dev/null || echo "?")
if [[ "$count" == "2" ]]; then
  ok "list merges wip-ref + archive-ref + vault into one row per item (2 items)"
else
  bad "list merges wip-ref + archive-ref + vault into one row per item (2 items)" "got $count rows: $out"
fi

sources1=$(printf '%s' "$out" | python3 -c "
import json, sys
rows = json.load(sys.stdin)
for r in rows:
    if r.get('vault_id') == '$ENTRY':
        print(','.join(sorted(r['sources'])))
        break
")
if [[ "$sources1" == "archive-ref,vault,wip-ref" ]]; then
  ok "the pushed item shows all three sources merged"
else
  bad "the pushed item shows all three sources merged" "got: $sources1"
fi

sources2=$(printf '%s' "$out" | python3 -c "
import json, sys
rows = json.load(sys.stdin)
for r in rows:
    if r.get('vault_id') == '$ENTRY2':
        print(','.join(sorted(r['sources'])))
        break
")
if [[ "$sources2" == "archive-ref,vault" ]]; then
  ok "the archive-only item shows vault + archive-ref, no wip-ref"
else
  bad "the archive-only item shows vault + archive-ref, no wip-ref" "got: $sources2"
fi

# ---------------------------------------------------------------------------
# restore: reproduces tracked + untracked + secret files byte-identical
# ---------------------------------------------------------------------------

restore_out=$(python3 "$CLI" --vault-root "$VAULT" restore "$ENTRY" --repo "$REPO_ABS" --json 2>"$TMP/err")
rc=$?
if [[ $rc -eq 0 ]]; then ok "restore of vault entry exits 0"; else bad "restore of vault entry exits 0" "rc=$rc err=$(cat "$TMP/err")"; fi

DEST=$(json_field "worktree" "$restore_out" 2>/dev/null)
if [[ -n "$DEST" && -d "$DEST" ]]; then ok "restore reports a worktree path that exists"; else bad "restore reports a worktree path that exists" "restore_out=$restore_out"; fi

if [[ -f "$DEST/tracked.txt" && "$(cat "$DEST/tracked.txt")" == "modified tracked" ]]; then
  ok "restore reproduces the modified tracked file"
else
  bad "restore reproduces the modified tracked file" "content=$(cat "$DEST/tracked.txt" 2>/dev/null || echo MISSING)"
fi

if [[ -f "$DEST/notes.txt" && "$(cat "$DEST/notes.txt")" == "plain untracked" ]]; then
  ok "restore reproduces the untracked file byte-identical"
else
  bad "restore reproduces the untracked file byte-identical" "content=$(cat "$DEST/notes.txt" 2>/dev/null || echo MISSING)"
fi

if [[ -f "$DEST/.env" && "$(cat "$DEST/.env")" == "super secret token" ]]; then
  ok "restore reproduces the secret file byte-identical"
else
  bad "restore reproduces the secret file byte-identical" "content=$(cat "$DEST/.env" 2>/dev/null || echo MISSING)"
fi

if [[ -d "$DEST/.secretdir" ]]; then
  ok "restore reproduces the untracked directory"
else
  bad "restore reproduces the untracked directory" "missing $DEST/.secretdir"
fi

# ---------------------------------------------------------------------------
# second restore of the same item refuses, names the existing path
# ---------------------------------------------------------------------------

second_err=$(python3 "$CLI" --vault-root "$VAULT" restore "$WIP_REF" --repo "$REPO_ABS" 2>&1 >/dev/null)
rc2=$?
if [[ $rc2 -eq 3 ]]; then ok "second restore (via wip ref) refuses with exit 3"; else bad "second restore (via wip ref) refuses with exit 3" "rc=$rc2 out=$second_err"; fi
if [[ "$second_err" == *"$DEST"* ]]; then
  ok "the refusal names the existing path"
else
  bad "the refusal names the existing path" "err=$second_err dest=$DEST"
fi
if [[ ! -e "$REPO_ABS/.worktrees/wip-${SHA7}-2" ]]; then
  ok "no -2 duplicate worktree was created"
else
  bad "no -2 duplicate worktree was created" "found a -2 dupe"
fi

# ---------------------------------------------------------------------------
# archive-only entry (no wip ref) restores from vault + archived sha alone
# ---------------------------------------------------------------------------

restore2_out=$(python3 "$CLI" --vault-root "$VAULT" restore "$ENTRY2" --repo "$REPO_ABS" --json 2>"$TMP/err2")
rc3=$?
if [[ $rc3 -eq 0 ]]; then ok "restore of archive-only vault entry exits 0"; else bad "restore of archive-only vault entry exits 0" "rc=$rc3 err=$(cat "$TMP/err2")"; fi

DEST2=$(json_field "worktree" "$restore2_out" 2>/dev/null)
if [[ -f "$DEST2/.env" && "$(cat "$DEST2/.env")" == "bar secret" ]]; then
  ok "archive-only restore reproduces the secret file from the delta alone"
else
  bad "archive-only restore reproduces the secret file from the delta alone" "content=$(cat "$DEST2/.env" 2>/dev/null || echo MISSING)"
fi

echo
echo "PASS=$PASS FAIL=$FAIL"
[[ "$FAIL" -eq 0 ]]
