#!/usr/bin/env bash
# od-worktree — create/remove git worktrees INSIDE the repo, never in $HOME.
#
# CONTRACT
#   od-worktree add <name> [<committish>]   -> <repo-root>/.worktrees/<name> on branch wt/<name>
#   od-worktree list                        -> every worktree of this repo, flagging out-of-repo ones
#   od-worktree remove <name> [--force]
#   od-worktree adopt <path>                -> move an existing out-of-repo worktree into .worktrees/
#
# <name> is a bare slug — never a path. A path, an absolute destination, or any escape via ".."
# is refused. There is no flag to place a worktree outside the repo.

set -euo pipefail

die() { printf 'od-worktree: %s\n' "$1" >&2; exit 2; }

REPO_ROOT="$(git rev-parse --path-format=absolute --show-toplevel 2>/dev/null)" || die "not inside a git repository"
COMMON_DIR="$(git rev-parse --path-format=absolute --git-common-dir)"
MAIN_ROOT="$(cd "$COMMON_DIR/.." && pwd)"
WT_DIR="$MAIN_ROOT/.worktrees"

# shim-drift-check runs from a deploy clone with no link back to a dev checkout, so the
# checkouts that hold worktrees are recorded where it can find them.
register_checkout() {
  local file="${OD_SHIM_REPOS_FILE:-$HOME/.local/state/overdeck/shim-repos}" tmp ok=1
  if [[ -r "$file" ]] && grep -qxF "$MAIN_ROOT" "$file"; then
    return 0
  fi
  tmp="$file.$$"
  if mkdir -p "$(dirname "$file")"; then
    if [[ -f "$file" ]]; then
      cp "$file" "$tmp" || ok=0
    else
      : >"$tmp" || ok=0
    fi
    if ((ok)); then
      printf '%s\n' "$MAIN_ROOT" >>"$tmp" && mv "$tmp" "$file" || ok=0
    fi
  else
    ok=0
  fi
  if ((ok == 0)); then
    rm -f "$tmp"
    printf 'od-worktree: cannot record %s in %s — shim-drift-check will not see this checkout\n' "$MAIN_ROOT" "$file" >&2
  fi
}
register_checkout

require_slug() {
  local name="${1:-}"
  [[ -n "$name" ]] || die "name required"
  [[ "$name" =~ ^[A-Za-z0-9][A-Za-z0-9._-]*$ ]] || die "name must be a bare slug (got '$name'); worktrees are always created under $WT_DIR"
}

cmd_add() {
  local name="${1:-}" base="${2:-}"
  require_slug "$name"
  local dest="$WT_DIR/$name"
  [[ -e "$dest" ]] && die "$dest already exists"
  mkdir -p "$WT_DIR"
  if [[ -z "$base" ]]; then
    base="$(git symbolic-ref --quiet --short refs/remotes/origin/HEAD 2>/dev/null || echo origin/main)"
  fi
  local branch="wt/$name"
  if git show-ref --verify --quiet "refs/heads/$branch"; then
    git worktree add "$dest" "$branch"
  else
    git worktree add -b "$branch" "$dest" "$base"
  fi
  printf '%s\n' "$dest"
}

cmd_list() {
  git worktree list --porcelain | awk -v root="$MAIN_ROOT" '
    /^worktree /{
      path = substr($0, 10)
      inside = (index(path, root "/") == 1 || path == root)
      printf "%s%s\n", path, inside ? "" : "   <- OUTSIDE THE REPO"
    }'
}

cmd_remove() {
  local name="${1:-}"; shift || true
  require_slug "$name"
  git worktree remove "$WT_DIR/$name" "$@"
}

cmd_adopt() {
  local src="${1:-}"
  [[ -n "$src" ]] || die "path required"
  src="$(cd "$src" && pwd)" || die "no such directory"
  [[ "$src" == "$MAIN_ROOT" ]] && die "refusing to move the main checkout"
  case "$src" in "$MAIN_ROOT"/*) die "$src is already inside the repo";; esac
  git worktree list --porcelain | grep -qx "worktree $src" || die "$src is not a worktree of this repo"
  mkdir -p "$WT_DIR"
  local dest="$WT_DIR/$(basename "$src")"
  [[ -e "$dest" ]] && die "$dest already exists"
  git worktree move "$src" "$dest"
  printf '%s\n' "$dest"
}

case "${1:-}" in
  add)    shift; cmd_add "$@";;
  list)   shift; cmd_list "$@";;
  remove) shift; cmd_remove "$@";;
  adopt)  shift; cmd_adopt "$@";;
  *) die "usage: od-worktree {add <name> [<base>]|list|remove <name>|adopt <path>}";;
esac
