# Built-in initialization script for just-bash-nx CLI.
# This file is sourced implicitly unless --no-init is provided.

export JUST_BASH=1


# Reusable host-command mocks for npx just-bash-nx verification.
# Source this file inside the same shell process as the script under test.

# ---------- helpers ----------
_mock_now_ms() {
  date +%s000
}

_mock_escape_json() {
  # Minimal JSON string escaper for test data.
  printf '%s' "$1" | awk 'BEGIN { RS=""; ORS="" } { gsub(/\\/, "\\\\"); gsub(/"/, "\\\""); gsub(/\t/, "\\t"); gsub(/\r/, "\\r"); gsub(/\n/, "\\n"); printf "%s", $0 }'
}

# Parse repeatable flags as lines into stdout.
# usage: _mock_collect_flag_values "--jid" "$@"
_mock_collect_flag_values() {
  flag="$1"
  shift
  while [ "$#" -gt 0 ]; do
    if [ "$1" = "$flag" ]; then
      if [ "$#" -ge 2 ]; then
        printf '%s\n' "$2"
        shift 2
        continue
      fi
    fi
    shift
  done
  return 0
}

_mock_find_next() {
  flag="$1"
  shift
  while [ "$#" -gt 0 ]; do
    if [ "$1" = "$flag" ]; then
      if [ "$#" -ge 2 ]; then
        printf '%s' "$2"
        return 0
      fi
    fi
    shift
  done
  return 1
}

_mock_has_flag() {
  flag="$1"
  shift
  while [ "$#" -gt 0 ]; do
    if [ "$1" = "$flag" ]; then
      return 0
    fi
    shift
  done
  return 1
}

# ---------- command mocks ----------

fetch-messages() {
  thread_ts="$(_mock_find_next --thread-timestamp "$@" || true)"
  days="$(_mock_find_next --days "$@" || true)"
  if [ -z "$days" ]; then
    days=2
  fi

  ts="$(_mock_now_ms)"
  msg_text="mock message"
  if [ -n "$thread_ts" ]; then
    msg_text="mock message for thread ${thread_ts}"
    ts="$thread_ts"
  fi

  cat <<JSON
{"messages":[{"messageId":"m-1","content":"$(_mock_escape_json "$msg_text")","time":$ts,"senderJid":"mock.user@xmpp.zoom.us"}],"participants":[{"jid":"mock.user@xmpp.zoom.us","displayName":"Mock User"}],"currentUser":{"jid":"me@xmpp.zoom.us","displayName":"Me"},"meta":{"days":$days,"threadTimestamp":"$(_mock_escape_json "${thread_ts:-}")"}}
JSON
}

get-user() {
  jid="$(_mock_find_next --jid "$@" || true)"
  query="$(_mock_find_next --query "$@" || true)"
  email="$(_mock_find_next --email "$@" || true)"

  if [ -n "$jid" ]; then
    cat <<JSON
{"matchType":"exact","query":"$(_mock_escape_json "$jid")","user":{"jid":"$(_mock_escape_json "$jid")","displayName":"Mock By JID","email":"mock@zoom.us"}}
JSON
    return 0
  fi

  if [ -n "$query" ]; then
    cat <<JSON
{"matchType":"exact","query":"$(_mock_escape_json "$query")","user":{"jid":"mock.query@xmpp.zoom.us","displayName":"$(_mock_escape_json "$query")"}}
JSON
    return 0
  fi

  if [ -n "$email" ]; then
    cat <<JSON
{"matchType":"exact","query":"$(_mock_escape_json "$email")","user":{"jid":"mock.email@xmpp.zoom.us","displayName":"Mock By Email","email":"$(_mock_escape_json "$email")"}}
JSON
    return 0
  fi

  echo '{"matchType":"not_found","query":"","candidates":[]}'
}

send-chat() {
  sid="$(_mock_find_next --session-id "$@" || true)"
  content="$(_mock_find_next --content "$@" || true)"
  thread_ts="$(_mock_find_next --thread-timestamp "$@" || true)"
  if [ -z "$sid" ]; then
    sid="mock-session"
  fi

  cat <<JSON
{"messageId":"msg-$(_mock_now_ms)","sessionId":"$(_mock_escape_json "$sid")","echo":{"content":"$(_mock_escape_json "${content:-}")","threadTimestamp":"$(_mock_escape_json "${thread_ts:-}")"}}
JSON
}

forward-thread() {
  to_sid="$(_mock_find_next --to-session-id "$@" || true)"
  from_sid="$(_mock_find_next --from-session-id "$@" || true)"
  thread_ts="$(_mock_find_next --thread-timestamp "$@" || true)"
  if [ -z "$to_sid" ]; then
    to_sid="mock-destination-session"
  fi
  if [ -z "$from_sid" ]; then
    from_sid="mock-source-session"
  fi
  if [ -z "$thread_ts" ]; then
    thread_ts="$(_mock_now_ms)"
  fi

  cat <<JSON
{"messageId":"forward-thread-$(_mock_now_ms)","echo":{"toSessionId":"$(_mock_escape_json "$to_sid")","fromSessionId":"$(_mock_escape_json "$from_sid")","threadTimestamp":"$(_mock_escape_json "$thread_ts")"}}
JSON
}

forward-messages() {
  to_sid="$(_mock_find_next --to-session-id "$@" || true)"
  from_sid="$(_mock_find_next --from-session-id "$@" || true)"
  message_ids="$(_mock_find_next --message-ids "$@" || true)"
  if [ -z "$to_sid" ]; then
    to_sid="mock-destination-session"
  fi
  if [ -z "$from_sid" ]; then
    from_sid="mock-source-session"
  fi
  if [ -z "$message_ids" ]; then
    message_ids="msg-1"
  fi

  message_ids_json='['
  first_id=1
  for message_id in $(printf '%s' "$message_ids" | tr ',' ' '); do
    if [ -z "$message_id" ]; then
      continue
    fi
    if [ "$first_id" -eq 0 ]; then
      message_ids_json="${message_ids_json},"
    fi
    message_ids_json="${message_ids_json}\"$(_mock_escape_json "$message_id")\""
    first_id=0
  done
  message_ids_json="${message_ids_json}]"

  cat <<JSON
{"messageId":"forward-messages-$(_mock_now_ms)","echo":{"toSessionId":"$(_mock_escape_json "$to_sid")","fromSessionId":"$(_mock_escape_json "$from_sid")","messageIds":"$(_mock_escape_json "$message_ids")"},"messageIds":$message_ids_json}
JSON
}

edit-chat() {
  sid="$(_mock_find_next --session-id "$@" || true)"
  mid="$(_mock_find_next --message-id "$@" || true)"
  content="$(_mock_find_next --content "$@" || true)"
  if [ -z "$sid" ]; then
    sid="mock-session"
  fi
  if [ -z "$mid" ]; then
    mid="mock-message-id"
  fi

  cat <<JSON
{"ok":true,"sessionId":"$(_mock_escape_json "$sid")","messageId":"$(_mock_escape_json "$mid")","updatedContent":"$(_mock_escape_json "${content:-}")"}
JSON
}

add-members() {
  sid="$(_mock_find_next --session-id "$@" || true)"
  if [ -z "$sid" ]; then
    sid="mock-session"
  fi

  jids="$(_mock_collect_flag_values --jid "$@")"
  emails="$(_mock_collect_flag_values --email "$@")"

  invited=0
  if [ -n "$jids" ]; then
    invited=$((invited + $(printf '%s\n' "$jids" | sed '/^$/d' | wc -l | tr -d ' ')))
  fi
  if [ -n "$emails" ]; then
    invited=$((invited + $(printf '%s\n' "$emails" | sed '/^$/d' | wc -l | tr -d ' ')))
  fi

  first_jid=""
  if [ -n "$jids" ]; then
    first_jid="$(printf '%s\n' "$jids" | sed -n '1p')"
  fi

  if [ -n "$first_jid" ]; then
    if [ "${MOCK_ADD_MEMBERS_DENY_FIRST:-0}" = "1" ]; then
      cat <<JSON
{"sessionId":"$(_mock_escape_json "$sid")","invitedCount":$((invited-1)),"notAllowedList":[{"jid":"$(_mock_escape_json "$first_jid")","reason":"mock_denied"}],"echo":{"jids":"$(_mock_escape_json "$jids")","emails":"$(_mock_escape_json "$emails")"}}
JSON
      return 0
    fi
  fi

  cat <<JSON
{"sessionId":"$(_mock_escape_json "$sid")","invitedCount":$invited,"notAllowedList":[],"echo":{"jids":"$(_mock_escape_json "$jids")","emails":"$(_mock_escape_json "$emails")"}}
JSON
}

add-mention-group() {
  sid="$(_mock_find_next --session-id "$@" || true)"
  name="$(_mock_find_next --name "$@" || true)"
  desc="$(_mock_find_next --description "$@" || true)"
  members="$(_mock_collect_flag_values --member "$@")"
  if [ -z "$sid" ]; then
    sid="mock-session"
  fi
  if [ -z "$name" ]; then
    name="@mock"
  fi
  member_count=0
  if [ -n "$members" ]; then
    member_count="$(printf '%s\n' "$members" | sed '/^$/d' | wc -l | tr -d ' ')"
  fi

  cat <<JSON
{"ok":true,"channelId":"$(_mock_escape_json "$sid")","name":"$(_mock_escape_json "$name")","description":"$(_mock_escape_json "${desc:-}")","memberCount":$member_count}
JSON
}

get-members() {
  sid="$(_mock_find_next --session-id "$@" || true)"
  if [ -z "$sid" ]; then
    sid="mock-session"
  fi
  force="false"
  if _mock_has_flag --force-update "$@"; then
    force="true"
  fi

  cat <<JSON
{"sessionId":"$(_mock_escape_json "$sid")","memberCount":2,"members":[{"jid":"a@xmpp.zoom.us"},{"jid":"b@xmpp.zoom.us"}],"pendingMembers":[],"meta":{"forceUpdate":$force}}
JSON
}

create-channel() {
  name="$(_mock_find_next --name "$@" || true)"
  if [ -z "$name" ]; then
    name="~mock"
  fi
  public=false
  if _mock_has_flag --public "$@"; then
    public=true
  fi
  jids="$(_mock_collect_flag_values --jid "$@")"

  cat <<JSON
{"id":"$(_mock_escape_json "${name}@conference.xmpp.zoom.us")","jid":"$(_mock_escape_json "${name}@conference.xmpp.zoom.us")","channelId":"$(_mock_escape_json "sid-${name}")","subject":"$(_mock_escape_json "$name")","meta":{"isPublic":$public,"jids":"$(_mock_escape_json "$jids")"}}
JSON
}

get-channel() {
  name="$(_mock_find_next --name "$@" || true)"
  if [ -z "$name" ]; then
    name="~mock"
  fi
  if [ "$name" = "~missing" ]; then
    echo '{"found":false,"subject":"~missing","reason":"not_found","message":"Channel \"~missing\" was not found."}'
    return 0
  fi

  cat <<JSON
{"id":"$(_mock_escape_json "${name}@conference.xmpp.zoom.us")","jid":"$(_mock_escape_json "${name}@conference.xmpp.zoom.us")","channelId":"$(_mock_escape_json "sid-${name}")","subject":"$(_mock_escape_json "$name")","deeplink":"zoommtg://chat?sid=$(_mock_escape_json "sid-${name}")"}
JSON
}

open-session() {
  sid="$(_mock_find_next --session-id "$@" || true)"
  if [ -z "$sid" ]; then
    sid="mock-session"
  fi

  cat <<JSON
{"ok":true,"sessionId":"$(_mock_escape_json "$sid")","deeplink":"zoommtg://chat?sid=$(_mock_escape_json "$sid")"}
JSON
}

make-deeplink() {
  sid="$(_mock_find_next --sid "$@" || true)"
  mid="$(_mock_find_next --mid "$@" || true)"
  time_value="$(_mock_find_next --time "$@" || true)"
  sid2="$(_mock_find_next --sid2 "$@" || true)"
  aiid="$(_mock_find_next --aiid "$@" || true)"
  if [ -z "$sid" ]; then
    sid="mock-session"
  fi

  deeplink="zoommtg://chat?sid=$(_mock_escape_json "$sid")"
  if [ -n "$mid" ]; then
    deeplink="${deeplink}&mid=$(_mock_escape_json "$mid")"
  fi
  if [ -n "$time_value" ]; then
    deeplink="${deeplink}&time=$(_mock_escape_json "$time_value")"
  fi
  if [ -n "$sid2" ]; then
    deeplink="${deeplink}&sid2=$(_mock_escape_json "$sid2")"
  fi
  if [ -n "$aiid" ]; then
    deeplink="${deeplink}&aiid=$(_mock_escape_json "$aiid")"
  fi

  cat <<JSON
{"deeplink":"$deeplink"}
JSON
}

calendar-create-event() {
  event_kind="$(_mock_find_next --event-kind "$@" || true)"
  organizer_mail="$(_mock_find_next --organizer-mail "$@" || true)"
  subject="$(_mock_find_next --subject "$@" || true)"
  start="$(_mock_find_next --start "$@" || true)"
  duration="$(_mock_find_next --duration "$@" || true)"
  description="$(_mock_find_next --description "$@" || true)"
  time_zone="$(_mock_find_next --time-zone "$@" || true)"
  location="$(_mock_find_next --location "$@" || true)"
  send_updates="$(_mock_find_next --send-updates "$@" || true)"
  attendees="$(_mock_collect_flag_values --attendee "$@")"

  if [ -z "$event_kind" ]; then
    event_kind="zoom_meeting"
  fi
  if [ -z "$organizer_mail" ]; then
    organizer_mail="primary"
  fi
  if [ -z "$subject" ]; then
    subject="Mock Event"
  fi
  if [ -z "$start" ]; then
    start="2026-06-11T09:00:00Z"
  fi
  if [ -z "$duration" ]; then
    duration="30"
  fi

  attendee_count=0
  attendees_json='[]'
  if [ -n "$attendees" ]; then
    attendee_count="$(printf '%s\n' "$attendees" | sed '/^$/d' | wc -l | tr -d ' ')"
    attendees_json='['
    first_attendee=1
    while IFS= read -r attendee; do
      if [ -z "$attendee" ]; then
        continue
      fi
      if [ "$first_attendee" -eq 0 ]; then
        attendees_json="${attendees_json},"
      fi
      attendees_json="${attendees_json}\"$(_mock_escape_json "$attendee")\""
      first_attendee=0
    done <<EOF
$attendees
EOF
    attendees_json="${attendees_json}]"
  fi

  cat <<JSON
{"event":{"id":"event-$(_mock_now_ms)","subject":"$(_mock_escape_json "$subject")","start":"$(_mock_escape_json "$start")","duration":$duration,"eventKind":"$(_mock_escape_json "$event_kind")","organizerMail":"$(_mock_escape_json "$organizer_mail")","description":"$(_mock_escape_json "${description:-}")","timeZone":"$(_mock_escape_json "${time_zone:-}")","location":"$(_mock_escape_json "${location:-}")","sendUpdates":"$(_mock_escape_json "${send_updates:-}")","attendeeCount":$attendee_count},"echo":{"attendees":$attendees_json}}
JSON
}

calendar-list-events() {
  owners="$(_mock_collect_flag_values --calendar-owner-mail "$@")"
  start="$(_mock_find_next --start "$@" || true)"
  duration="$(_mock_find_next --duration "$@" || true)"
  time_zone="$(_mock_find_next --time-zone "$@" || true)"
  if [ -z "$start" ]; then
    start="2026-06-11T09:00:00Z"
  fi
  if [ -z "$duration" ]; then
    duration="30"
  fi

  owner_count=0
  owners_json='[]'
  if [ -n "$owners" ]; then
    owner_count="$(printf '%s\n' "$owners" | sed '/^$/d' | wc -l | tr -d ' ')"
    owners_json='['
    first_owner=1
    while IFS= read -r owner; do
      if [ -z "$owner" ]; then
        continue
      fi
      if [ "$first_owner" -eq 0 ]; then
        owners_json="${owners_json},"
      fi
      owners_json="${owners_json}\"$(_mock_escape_json "$owner")\""
      first_owner=0
    done <<EOF
$owners
EOF
    owners_json="${owners_json}]"
  fi

  cat <<JSON
{"events":[{"id":"event-1","subject":"Mock Calendar Event","start":"$(_mock_escape_json "$start")","duration":$duration}],"meta":{"calendarOwnerCount":$owner_count,"calendarOwners":$owners_json,"timeZone":"$(_mock_escape_json "${time_zone:-}")"}}
JSON
}

calendar-get-free-busy() {
  owners="$(_mock_collect_flag_values --calendar-owner-mail "$@")"
  start="$(_mock_find_next --start "$@" || true)"
  end="$(_mock_find_next --end "$@" || true)"
  duration="$(_mock_find_next --duration "$@" || true)"
  time_zone="$(_mock_find_next --time-zone "$@" || true)"
  suggest_time=false
  if _mock_has_flag --suggest-time "$@"; then
    suggest_time=true
  fi
  if [ -z "$start" ]; then
    start="2026-06-11T09:00:00Z"
  fi
  if [ -z "$end" ]; then
    end="2026-06-11T10:00:00Z"
  fi
  if [ -z "$duration" ]; then
    duration="30"
  fi

  owner_count=0
  if [ -n "$owners" ]; then
    owner_count="$(printf '%s\n' "$owners" | sed '/^$/d' | wc -l | tr -d ' ')"
  fi

  cat <<JSON
{"busy":[],"suggestions":[{"start":"$(_mock_escape_json "$start")","end":"$(_mock_escape_json "$end")","duration":$duration}],"meta":{"calendarOwnerCount":$owner_count,"timeZone":"$(_mock_escape_json "${time_zone:-}")","suggestTime":$suggest_time}}
JSON
}

calendar-patch-event() {
  organizer_mail="$(_mock_find_next --organizer-mail "$@" || true)"
  event_id="$(_mock_find_next --event-id "$@" || true)"
  subject="$(_mock_find_next --subject "$@" || true)"
  start="$(_mock_find_next --start "$@" || true)"
  duration="$(_mock_find_next --duration "$@" || true)"
  description="$(_mock_find_next --description "$@" || true)"
  time_zone="$(_mock_find_next --time-zone "$@" || true)"
  location="$(_mock_find_next --location "$@" || true)"
  send_updates="$(_mock_find_next --send-updates "$@" || true)"
  attendees="$(_mock_collect_flag_values --attendee "$@")"
  if [ -z "$organizer_mail" ]; then
    organizer_mail="primary"
  fi
  if [ -z "$event_id" ]; then
    event_id="event-1"
  fi

  attendee_count=0
  if [ -n "$attendees" ]; then
    attendee_count="$(printf '%s\n' "$attendees" | sed '/^$/d' | wc -l | tr -d ' ')"
  fi

  cat <<JSON
{"event":{"id":"$(_mock_escape_json "$event_id")","subject":"$(_mock_escape_json "${subject:-Mock Patched Event}")","start":"$(_mock_escape_json "${start:-}")","duration":"$(_mock_escape_json "${duration:-}")","description":"$(_mock_escape_json "${description:-}")","timeZone":"$(_mock_escape_json "${time_zone:-}")","location":"$(_mock_escape_json "${location:-}")","organizerMail":"$(_mock_escape_json "$organizer_mail")","sendUpdates":"$(_mock_escape_json "${send_updates:-}")","attendeeCount":$attendee_count}}
JSON
}

calendar-delete-event() {
  organizer_mail="$(_mock_find_next --organizer-mail "$@" || true)"
  event_id="$(_mock_find_next --event-id "$@" || true)"
  send_updates="$(_mock_find_next --send-updates "$@" || true)"
  if [ -z "$organizer_mail" ]; then
    organizer_mail="primary"
  fi
  if [ -z "$event_id" ]; then
    event_id="event-1"
  fi

  cat <<JSON
{"ok":true,"eventId":"$(_mock_escape_json "$event_id")","calendarId":"$(_mock_escape_json "$organizer_mail")","sendUpdates":"$(_mock_escape_json "${send_updates:-all}")"}
JSON
}

create-or-update-skill() {
  content="$(_mock_find_next --content "$@" || true)"
  update_sid="$(_mock_find_next --update-session-id "$@" || true)"
  update_mid="$(_mock_find_next --update-message-id "$@" || true)"
  cmds="$(_mock_collect_flag_values --command "$@")"
  refs="$(_mock_collect_flag_values --reference "$@")"

  mode="create"
  if [ -n "$update_sid" ] || [ -n "$update_mid" ]; then
    mode="update"
  fi

  cat <<JSON
{"channelId":"${update_sid:-mock-session}","messageId":"skill-$(_mock_now_ms)","mode":"$mode","echo":{"content":"$(_mock_escape_json "${content:-}")","commands":"$(_mock_escape_json "$cmds")","references":"$(_mock_escape_json "$refs")","updateSessionId":"$(_mock_escape_json "${update_sid:-}")","updateMessageId":"$(_mock_escape_json "${update_mid:-}")"}}
JSON
}
