#!/usr/bin/env bash
# discord-dm.sh — send a Discord message to an org member (DM) or a team channel,
# using the ClaudeTools bot. Built for copy-paste-friendly delivery of wrapped
# command lines (consent links, long one-liners) straight to a person's DMs.
#
# Usage:
#   discord-dm.sh <recipient> "message text"
#   echo "message text" | discord-dm.sh <recipient>
#   discord-dm.sh read <recipient> [limit]   # READ recent messages — SEE replies (default 15)
#   discord-dm.sh list                       # show known users + channels
#
# <recipient> is one of:
#   - a user name:    mike | howard | rob | winter        -> opens a DM
#   - a channel:      #bot-alerts | #dev-alerts | bot | dev -> posts to the channel
#   - a raw snowflake: 17-19 digit ID (treated as a USER DM; prefix chan:<id> for a channel)
#
# Token resolution (mirrors post-bot-alert.sh, first hit wins):
#   1. SOPS vault: projects/discord-bot/bot-token.sops.yaml  field credentials.bot_token
#   2. projects/discord-bot/.env                              key  DISCORD_TOKEN
#
# Exit codes: 0 success; 1 usage/arg error; 2 token missing; 3 Discord API error.
# Unlike post-bot-alert.sh this does NOT soft-fail — a DM is usually load-bearing
# (you asked for it on purpose), so a failure is surfaced with a non-zero exit.

set -u

ROOT="${CLAUDETOOLS_ROOT:-$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)}"
API="https://discord.com/api/v10"
UA="ClaudeToolsBot (claudetools, 1.0)"

# --- prepopulated org directory (from .claude/users.json + post-bot-alert.sh) ---
declare -A USERS=(
  [mike]="264814939619721216"
  [howard]="624667664501178379"
  [rob]="261978810713505792"
  [winter]="624666486362996755"
)
declare -A CHANNELS=(
  [bot-alerts]="624710699771232265"   # whole team (Syncro + general)
  [dev-alerts]="1509998508198068484"  # private RMM/Dev (Howard + Mike)
)

print_dir() {
  echo "Users (DM):"
  for u in "${!USERS[@]}"; do printf "  %-8s %s\n" "$u" "${USERS[$u]}"; done
  echo "Channels:"
  for c in "${!CHANNELS[@]}"; do printf "  #%-12s %s\n" "$c" "${CHANNELS[$c]}"; done
}

RECIPIENT="${1:-}"
if [ -z "$RECIPIENT" ] || [ "$RECIPIENT" = "-h" ] || [ "$RECIPIENT" = "--help" ]; then
  sed -n '2,30p' "$0"; exit 1
fi
if [ "$RECIPIENT" = "list" ]; then print_dir; exit 0; fi

# --- read mode: fetch recent messages so we can SEE replies (mike/winter/etc.).
# `discord-dm.sh read <user|#channel> [limit]` — reuses the recipient resolution,
# token, and DM-channel-open below, then prints history instead of sending. The
# bot participates in each DM channel it opened, so REST history returns full
# content (the Message Content intent only gates gateway events, not this fetch).
ACTION=send
if [ "$RECIPIENT" = "read" ] || [ "$RECIPIENT" = "inbox" ]; then
  ACTION=read; shift
  RECIPIENT="${1:-}"
  [ -z "$RECIPIENT" ] && { echo "[ERROR] usage: discord-dm.sh read <user|#channel> [limit]" >&2; exit 1; }
fi
shift

# --- message (send) or limit (read) ---
if [ "$ACTION" = "read" ]; then
  READ_LIMIT="${1:-15}"
  printf '%s' "$READ_LIMIT" | grep -qE '^[0-9]+$' || READ_LIMIT=15
  [ "$READ_LIMIT" -gt 100 ] && READ_LIMIT=100
else
  if [ "$#" -gt 0 ]; then MSG="$*"; elif [ ! -t 0 ]; then MSG="$(cat)"; else MSG=""; fi
  if [ -z "$MSG" ]; then echo "[ERROR] empty message — nothing sent" >&2; exit 1; fi
fi

# --- resolve recipient -> mode (dm|channel) + target id ---
MODE=""; TARGET=""; LABEL=""
key="$(printf '%s' "$RECIPIENT" | tr '[:upper:]' '[:lower:]')"
case "$key" in
  bot|bot-alerts|"#bot-alerts") MODE=channel; TARGET="${CHANNELS[bot-alerts]}"; LABEL="#bot-alerts" ;;
  dev|dev-alerts|"#dev-alerts") MODE=channel; TARGET="${CHANNELS[dev-alerts]}"; LABEL="#dev-alerts" ;;
  chan:*)                        MODE=channel; TARGET="${key#chan:}"; LABEL="channel ${TARGET}" ;;
  \#*)                           c="${key#\#}"; if [ -n "${CHANNELS[$c]:-}" ]; then MODE=channel; TARGET="${CHANNELS[$c]}"; LABEL="#$c"; else echo "[ERROR] unknown channel: $RECIPIENT (try: discord-dm.sh list)" >&2; exit 1; fi ;;
  *)
    if [ -n "${USERS[$key]:-}" ]; then MODE=dm; TARGET="${USERS[$key]}"; LABEL="$key (DM)"
    elif printf '%s' "$key" | grep -qE '^[0-9]{17,19}$'; then MODE=dm; TARGET="$key"; LABEL="user ${key} (DM)"
    else echo "[ERROR] unknown recipient: $RECIPIENT (try: discord-dm.sh list)" >&2; exit 1; fi ;;
esac

# --- bot token: vault first, then .env ---
TOKEN="$(bash "$ROOT/.claude/scripts/vault.sh" get-field \
  projects/discord-bot/bot-token.sops.yaml credentials.bot_token 2>/dev/null)"
if [ -z "$TOKEN" ] || [ "$TOKEN" = "null" ]; then
  ENV_FILE="$ROOT/projects/discord-bot/.env"
  [ -f "$ENV_FILE" ] && TOKEN="$(grep -iE '^[[:space:]]*DISCORD_TOKEN[[:space:]]*=' "$ENV_FILE" | head -1 | sed -E 's/^[^=]*=[[:space:]]*//; s/^["'"'"']//; s/["'"'"'][[:space:]]*$//')"
fi
if [ -z "$TOKEN" ] || [ "$TOKEN" = "null" ]; then
  echo "[ERROR] no bot token (vault + .env both empty)" >&2
  bash "$ROOT/.claude/scripts/log-skill-error.sh" "discord-dm" "no Discord bot token (vault projects/discord-bot/bot-token + .env both empty)" >/dev/null 2>&1
  exit 2
fi

auth=(-H "Authorization: Bot ${TOKEN}" -H "Content-Type: application/json" -H "User-Agent: ${UA}")

# --- for a DM, open (or fetch) the user's DM channel ---
if [ "$MODE" = "dm" ]; then
  DM="$(printf '%s' "$(jq -nc --arg r "$TARGET" '{recipient_id:$r}')" | \
    curl -s -m 15 "${auth[@]}" -X POST "$API/users/@me/channels" --data-binary @-)"
  CHID="$(printf '%s' "$DM" | jq -r '.id // empty' 2>/dev/null)"
  if [ -z "$CHID" ]; then
    echo "[ERROR] could not open DM channel for $LABEL: $DM" >&2
    bash "$ROOT/.claude/scripts/log-skill-error.sh" "discord-dm" "failed to open DM channel for $LABEL" --context "resp=${DM:0:80}" >/dev/null 2>&1
    exit 3
  fi
  TARGET="$CHID"
fi

# --- read mode: fetch + print recent messages, then exit (no send) ---
if [ "$ACTION" = "read" ]; then
  MSGS="$(curl -s -m 20 "${auth[@]}" "$API/channels/${TARGET}/messages?limit=${READ_LIMIT}")"
  if ! printf '%s' "$MSGS" | jq -e 'type=="array"' >/dev/null 2>&1; then
    echo "[ERROR] could not read $LABEL: $(printf '%s' "$MSGS" | head -c 200)" >&2
    bash "$ROOT/.claude/scripts/log-skill-error.sh" "discord-dm" "read history failed for $LABEL" --context "resp=$(printf '%s' "$MSGS" | head -c 80)" >/dev/null 2>&1
    exit 3
  fi
  echo "[OK] discord-dm: last ${READ_LIMIT} message(s) in ${LABEL} (oldest first; '>>>' = reply from them, '   ' = us):"
  printf '%s' "$MSGS" | jq -r 'reverse[] |
    ((if (.author.bot // false) then "    " else ">>> " end)
      + (.timestamp[0:16]) + "  " + .author.username + ": "
      + ((.content // "") | gsub("\n";" ")))'
  exit 0
fi

# --- chunk: Discord caps content at 2000 chars (code 50035 on overflow).
# This tool's job is delivering LONG content intact, so split into <=1900-char
# pieces (preferring newline boundaries) and send them in order — no markers
# added, so the receiver can copy-paste the sequence back together verbatim.
LIMIT=1900
CHUNKS=()
rest="$MSG"
while [ "${#rest}" -gt "$LIMIT" ]; do
  piece="${rest:0:$LIMIT}"
  at_nl="${piece%$'\n'*}"                 # cut at the last newline in the window
  if [ "${#at_nl}" -lt "${#piece}" ] && [ "${#at_nl}" -gt 0 ]; then
    piece="$at_nl"
  fi
  CHUNKS+=("$piece")
  rest="${rest:${#piece}}"
  rest="${rest#$'\n'}"
done
CHUNKS+=("$rest")

# --- post the message (jq | --data-binary @- — argv/-d mangles multiline + non-ASCII JSON) ---
N=${#CHUNKS[@]}
i=0
for piece in "${CHUNKS[@]}"; do
  i=$((i+1))
  RESP="$(printf '%s' "$(jq -nc --arg c "$piece" '{content:$c}')" | \
    curl -s -m 15 -w $'\n%{http_code}' "${auth[@]}" \
    -X POST "$API/channels/${TARGET}/messages" --data-binary @-)"
  HTTP="$(printf '%s' "$RESP" | tail -n1)"
  BODY="$(printf '%s' "$RESP" | sed '$d')"
  if [ "$HTTP" != "200" ]; then
    echo "[ERROR] discord-dm: Discord returned ${HTTP:-no-response} on chunk ${i}/${N} — ${BODY}" >&2
    bash "$ROOT/.claude/scripts/log-skill-error.sh" "discord-dm" "Discord send to $LABEL failed (chunk ${i}/${N})" --context "http=${HTTP:-none} resp=${BODY:0:80}" >/dev/null 2>&1
    exit 3
  fi
done

if [ "$N" -gt 1 ]; then
  echo "[OK] discord-dm: sent to ${LABEL} in ${N} chunks (message_id=$(printf '%s' "$BODY" | jq -r '.id // empty'))"
else
  echo "[OK] discord-dm: sent to ${LABEL} (message_id=$(printf '%s' "$BODY" | jq -r '.id // empty'))"
fi
exit 0
