#!/usr/bin/env bash
# Example .jst/bootstrap.sh — the optional per-worktree bootstrap hook.
#
# THIS IS AN EXAMPLE, NOT A TEMPLATE TO FILL IN. Copy it to .jst/bootstrap.sh in
# your own project and rewrite it for your stack — nothing here is parsed, and
# there is no required structure. It is modelled on a Django + docker-compose
# project, because that is the case where per-worktree provisioning actually
# bites; a stateless frontend needs about six lines instead (see the bottom).
#
# WHAT RUNS THIS: jira-task-executor, in its step 1, once per worktree, at the
# moment someone is about to work in it — automatically, with no confirmation
# prompt. Its Windows twin is .jst/bootstrap.ps1. Why the executor and not the
# assigner: a multistep assigner run creates N worktrees in one unattended
# pass and would stand up N running environments at once.
#
# FAIL-SOFT: a non-zero exit is reported in the executor's output and the run
# continues. You cannot block the executor from here, so don't try — exit
# non-zero to say "this worktree isn't runnable yet", not "stop working".
#
# IDEMPOTENCY IS YOUR JOB: a re-run of the executor in the same worktree
# re-invokes this script. Every step below is create-if-missing or reuse.
#
# Full contract: skills/_shared/project-config.md § the optional worktree hook.
# Share-vs-isolate reasoning behind these decisions: docs/RUNNING-MULTIPLE-COPIES.md.

set -euo pipefail

# ---------------------------------------------------------------------------
# The environment contract. The executor exports all five; defaults here keep
# the script runnable by hand, which is how you'll debug it.
# ---------------------------------------------------------------------------
ISSUE_KEY="${JST_ISSUE_KEY:-$(git branch --show-current | sed -E 's#^[^/]+/([A-Z][A-Z0-9]+-[0-9]+).*#\1#')}"
WORKTREE_DIR="${JST_WORKTREE_DIR:-$(git rev-parse --show-toplevel)}"
BRANCH="${JST_BRANCH:-$(git branch --show-current)}"
PARENT_BRANCH="${JST_PARENT_BRANCH:-}"      # empty when unset — not an error
PROJECT_KEY="${JST_PROJECT_KEY:-PROJ}"

cd "$WORKTREE_DIR"

# ---------------------------------------------------------------------------
# The instance index. DERIVE IT DETERMINISTICALLY FROM THE ISSUE KEY — that is
# what makes the ports stable across re-runs and non-colliding across
# worktrees. Never allocate "the next free index": two worktrees bootstrapping
# at once would race, and the same worktree would drift between runs.
#
# Index 0 belongs to the main checkout's own stack, so map into 1..63 and leave
# it alone. Modulo means two issue numbers exactly 63 apart land on the same
# index (PROJ-226 and PROJ-289 both give 38), and nothing here detects that. It
# only bites when both are checked out at once, which is why this example takes
# the simple scheme — if your team runs enough parallel worktrees for it to be
# real, widen the range or add a collision check against the other worktrees.
# ---------------------------------------------------------------------------
ISSUE_NUM="${ISSUE_KEY##*-}"
INSTANCE=$(( (ISSUE_NUM % 63) + 1 ))

DB_PORT=$(( 55432 + INSTANCE ))
APP_PORT=$(( 8000 + INSTANCE ))
COMPOSE_PROJECT="$(echo "${PROJECT_KEY}" | tr '[:upper:]' '[:lower:]')-i${INSTANCE}"
STATE_DIR="$WORKTREE_DIR/.instances/$INSTANCE"

echo "bootstrap: $ISSUE_KEY on $BRANCH (parent: ${PARENT_BRANCH:-none})"
echo "bootstrap: instance $INSTANCE — db :$DB_PORT, app :$APP_PORT, compose $COMPOSE_PROJECT"

# ---------------------------------------------------------------------------
# 1. Per-instance state directory + rendered config. Idempotent: the directory
#    is mkdir -p, and the env file is rewritten from scratch each run so a
#    changed port scheme actually takes effect.
# ---------------------------------------------------------------------------
mkdir -p "$STATE_DIR/pgdata" "$STATE_DIR/uploads"

cat > "$WORKTREE_DIR/.env.local" <<ENV
# Generated by .jst/bootstrap.sh for $ISSUE_KEY — do not edit by hand.
DB_HOST=localhost
DB_PORT=$DB_PORT
DB_NAME=myapp
MEDIA_ROOT=$STATE_DIR/uploads
DEV_SERVER_PORT=$APP_PORT
ENV

# Secrets are NOT re-derived — copy them from the main checkout, which stays
# their single source of truth. `git worktree list` finds it without guessing.
MAIN_CHECKOUT=$(git worktree list --porcelain | awk '/^worktree /{print $2; exit}')
if [ -f "$MAIN_CHECKOUT/.env.secrets" ]; then
  cp "$MAIN_CHECKOUT/.env.secrets" "$WORKTREE_DIR/.env.secrets"
fi

# ---------------------------------------------------------------------------
# 2. Dependencies. Each worktree has its own node_modules / virtualenv.
#    Cheap to skip when already satisfied, so check before spending the time.
# ---------------------------------------------------------------------------
if [ ! -d "$WORKTREE_DIR/.venv" ]; then
  python3 -m venv "$WORKTREE_DIR/.venv"
fi
"$WORKTREE_DIR/.venv/bin/pip" install -q -r requirements.txt

# ---------------------------------------------------------------------------
# 3. This instance's database container. `up -d` is already idempotent — it
#    reuses a running container rather than erroring — which is why this is
#    plain `up` and not a stop/rm/create dance.
# ---------------------------------------------------------------------------
DB_PORT="$DB_PORT" PGDATA_DIR="$STATE_DIR/pgdata" \
  docker compose -p "$COMPOSE_PROJECT" -f docker-compose.worktree.yml up -d

# Wait for it rather than racing the migration below.
for _ in $(seq 1 30); do
  if pg_isready -h localhost -p "$DB_PORT" -q; then break; fi
  sleep 1
done

# ---------------------------------------------------------------------------
# 4. Seed the database — only when it's empty. This is the step that most
#    needs the idempotency guard: re-running the executor must not wipe work
#    already done in this worktree.
# ---------------------------------------------------------------------------
if [ ! -f "$STATE_DIR/.seeded" ]; then
  if [ -f "$MAIN_CHECKOUT/appdb.sql" ]; then
    psql -h localhost -p "$DB_PORT" -U myapp -d myapp -q -f "$MAIN_CHECKOUT/appdb.sql"
    touch "$STATE_DIR/.seeded"
  else
    # Non-zero: this worktree isn't fully runnable, and the executor will say
    # so and carry on. Tell the human exactly how to finish the job.
    echo "bootstrap: no baseline dump at $MAIN_CHECKOUT/appdb.sql — the database is empty." >&2
    echo "bootstrap: produce one with 'pg_dump -U myapp -d myapp > appdb.sql' from the main checkout, then re-run." >&2
    exit 1
  fi
fi

"$WORKTREE_DIR/.venv/bin/python" manage.py migrate --noinput

echo "bootstrap: ready — start the app with '.venv/bin/python manage.py runserver 0.0.0.0:$APP_PORT'"

# ---------------------------------------------------------------------------
# IF YOUR PROJECT IS STATELESS, THIS FILE IS MUCH SHORTER.
# A frontend or stateless service has no external state to duplicate, only a
# port to move. The whole hook can legitimately be:
#
#   #!/usr/bin/env bash
#   set -euo pipefail
#   cd "${JST_WORKTREE_DIR:-$(git rev-parse --show-toplevel)}"
#   npm install --silent
#   PORT=$(( 5174 + (${JST_ISSUE_KEY##*-} % 100) ))
#   printf 'PORT=%s\n' "$PORT" > .env.local
#   echo "bootstrap: run 'npm run dev' — it will serve on :$PORT"
#
# Write the shorter version rather than padding it out to look like the one
# above. The hook earns its place by doing what someone would otherwise have
# to work out by hand — not by covering every step in this example.
# ---------------------------------------------------------------------------
