#!/usr/bin/env bats

load 'helpers'

setup() {
  setup_party_sandbox
  require_party_group
}

teardown() { teardown_party_sandbox; }

party_rec() { printf '%s/party-%s:%s.d/roster\n' "$PARTY_SOCKET_DIR" "$USER" "$1"; }

@test "party list shows live parties only" {
  "$PARTY_BIN" host alpha
  "$PARTY_BIN" host bravo

  # Inject a fake stale record. The per-party dir must exist with the
  # right group + mode so roster_list can find the record inside.
  zdir="$PARTY_SOCKET_DIR/party-$USER:zombie.d"
  mkdir -p "$zdir"
  chgrp "$TMUX_PARTY_GROUP" "$zdir"
  chmod 0750 "$zdir"
  rec="$zdir/roster"
  cat > "$rec" <<EOF
HOST_USER=$USER
PARTY_NAME=zombie
SOCKET=$zdir/sock
SERVER_PID=999999
CREATED=2026-04-26T18:42:00Z
EOF
  chgrp "$TMUX_PARTY_GROUP" "$rec"
  chmod 0640 "$rec"

  run "$PARTY_BIN" list
  [ "$status" -eq 0 ]
  [[ "$output" == *"alpha"* ]]
  [[ "$output" == *"bravo"* ]]
  [[ "$output" != *"zombie"* ]]
}

@test "party list with no parties is friendly, not noisy" {
  run "$PARTY_BIN" list
  [ "$status" -eq 0 ]
  [[ "$output" == *"no parties"* ]]
}

# Cross-user discovery regression. Earlier revisions of is_party_alive
# probed the PID with `kill -0`, which returns EPERM under POSIX semantics
# when the caller can't signal the target — illumos, all BSDs, and macOS
# honor that, so guests couldn't discover parties hosted by other users
# on the same box. To simulate the foreign-uid case without privilege,
# rewrite the roster's SERVER_PID to 1 (init/launchd, root-owned on every
# supported platform) and confirm `party list`/`join` still find it. With
# the bug present this test fails on every non-Linux target; on Linux and
# Linux-ABI zones it passes regardless because Linux's kill(2) returns 0
# for "exists, even if not signalable."
@test "party list discovers parties whose host PID we cannot signal" {
  "$PARTY_BIN" host crossuser

  rec=$(party_rec crossuser)
  [ -f "$rec" ]
  # Rewrite SERVER_PID=<our-pid> -> SERVER_PID=1 in place. Avoids `sed -i`
  # portability snags between GNU and BSD sed.
  awk -F= 'BEGIN{OFS="="} $1=="SERVER_PID"{$2="1"} {print}' "$rec" >"$rec.new"
  cat "$rec.new" >"$rec"
  rm -f "$rec.new"

  run "$PARTY_BIN" list
  [ "$status" -eq 0 ]
  [[ "$output" == *"crossuser"* ]]

  PARTY_DRY_RUN=1 run "$PARTY_BIN" join crossuser
  [ "$status" -eq 0 ]
}

@test "party join <name> attaches via a guest session in group mode" {
  "$PARTY_BIN" host joinable

  rec=$(party_rec joinable)
  sock=$(awk -F= '$1=="SOCKET"{print $2}' "$rec")

  # Joining is interactive (it execs into tmux). We can't test the attach
  # without a real terminal, so we exercise the underlying path: with
  # PARTY_DRY_RUN=1 the join function builds the guest session and prints
  # the command that WOULD be exec'd, then exits.
  PARTY_DRY_RUN=1 "$PARTY_BIN" join joinable

  tmux -S "$sock" has-session -t "__party_guest_$USER"
}

@test "party join with no name auto-attaches single live party" {
  "$PARTY_BIN" host onlyone
  PARTY_DRY_RUN=1 "$PARTY_BIN" join
  rec=$(party_rec onlyone)
  sock=$(awk -F= '$1=="SOCKET"{print $2}' "$rec")
  tmux -S "$sock" has-session -t "__party_guest_$USER"
}

@test "party join with no name and no parties errors clearly" {
  run "$PARTY_BIN" join
  [ "$status" -ne 0 ]
  [[ "$output" == *"no parties"* ]]
}

@test "party join --passive attaches read-only to host session, no guest session" {
  "$PARTY_BIN" host mirror
  rec=$(party_rec mirror)
  sock=$(awk -F= '$1=="SOCKET"{print $2}' "$rec")
  # --passive must use `attach -r` so a write-capable invitee who chooses
  # passive can't type into the host's panes (the README's "watcher"
  # boundary). PARTY_DRY_RUN=1 prints the attach command instead of execing.
  run env PARTY_DRY_RUN=1 "$PARTY_BIN" join mirror --passive
  [ "$status" -eq 0 ]
  [[ "$output" == *"attach-session -r -t mirror"* ]]
  ! tmux -S "$sock" has-session -t "__party_guest_$USER" 2>/dev/null
}

@test "party leave kills the guest session and detaches the client" {
  "$PARTY_BIN" host leaveme
  rec=$(party_rec leaveme)
  sock=$(awk -F= '$1=="SOCKET"{print $2}' "$rec")

  PARTY_DRY_RUN=1 "$PARTY_BIN" join leaveme
  tmux -S "$sock" has-session -t "__party_guest_$USER"

  "$PARTY_BIN" leave
  ! tmux -S "$sock" has-session -t "__party_guest_$USER" 2>/dev/null
}

@test "party leave with no joined party errors helpfully" {
  run "$PARTY_BIN" leave
  [ "$status" -ne 0 ]
  [[ "$output" == *"not joined"* ]]
}
