#!/usr/bin/env bash
# logshq — E2E-encrypted log/status streams for agents.
# The key never leaves this machine: events are AES-256-CBC encrypted here,
# the server only ever stores ciphertext.
set -euo pipefail

SERVER="${LOGSHQ_SERVER:-https://logshq.com}"

usage() {
  cat >&2 <<'EOF'
usage:
  eval "$(logshq new [ttl_seconds])"   create a stream, export env, print watch url
  logshq log <message>                 post a log line
  logshq status <phase> [0..1] [msg]   post/update pinned status (+optional progress)
  logshq post <log|status> <json>      post raw event json (encrypted as-is)
  ... | logshq pipe                    post each stdin line as a log (passes through)

env: LOGSHQ_SERVER LOGSHQ_STREAM LOGSHQ_TOKEN LOGSHQ_KEY (set by `new`)
EOF
  exit 1
}

# ponytail: sed-based json field grab; we control the server's response shape
field() { printf '%s' "$1" | sed -n "s/.*\"$2\":\"\([^\"]*\)\".*/\1/p"; }

# escape " and \ and drop control chars — enough for one-line log messages
esc() { printf '%s' "$1" | tr -d '\000-\037' | sed -e 's/\\/\\\\/g' -e 's/"/\\"/g'; }

now() { date -u +%FT%TZ; }

require_stream() {
  : "${LOGSHQ_STREAM:?no stream — run: eval \"\$(logshq new)\"}"
  : "${LOGSHQ_TOKEN:?LOGSHQ_TOKEN not set}"
  : "${LOGSHQ_KEY:?LOGSHQ_KEY not set}"
}

post_event() { # $1 kind, $2 plaintext json
  require_stream
  local iv ct
  iv="$(openssl rand -hex 16)"
  ct="$(printf '%s' "$2" | openssl enc -aes-256-cbc -K "$LOGSHQ_KEY" -iv "$iv" | xxd -p | tr -d '\n')"
  curl -fsS -X POST "$SERVER/api/streams/$LOGSHQ_STREAM/events" \
    -H "authorization: Bearer $LOGSHQ_TOKEN" \
    -H 'content-type: application/json' \
    -d "{\"kind\":\"$1\",\"iv\":\"$iv\",\"ct\":\"$ct\"}" >/dev/null
}

cmd_new() {
  local ttl="${1:-}" body="{}" key resp id token
  [ -n "$ttl" ] && body="{\"ttl\":$ttl}"
  key="$(openssl rand -hex 32)"
  resp="$(curl -fsS -X POST "$SERVER/api/streams" -H 'content-type: application/json' -d "$body")"
  id="$(field "$resp" id)"
  token="$(field "$resp" token)"
  [ -n "$id" ] && [ -n "$token" ] || { echo "logshq: unexpected response: $resp" >&2; exit 1; }

  cat <<EOF
export LOGSHQ_SERVER="$SERVER"
export LOGSHQ_STREAM="$id"
export LOGSHQ_TOKEN="$token"
export LOGSHQ_KEY="$key"
export LOGSHQ_WATCH="$SERVER/s/$id#$key"
EOF
  printf '\nwatch (key stays in the #fragment, never sent to the server):\n  %s\n' "$SERVER/s/$id#$key" >&2
}

cmd_log() {
  [ $# -ge 1 ] || usage
  post_event log "{\"v\":1,\"type\":\"log\",\"ts\":\"$(now)\",\"msg\":\"$(esc "$*")\"}"
}

cmd_status() {
  [ $# -ge 1 ] || usage
  local phase="$1" progress="${2:-}" msg="${3:-}" json
  json="{\"v\":1,\"type\":\"status\",\"ts\":\"$(now)\",\"phase\":\"$(esc "$phase")\""
  [ -n "$progress" ] && json="$json,\"progress\":$progress"
  [ -n "$msg" ] && json="$json,\"msg\":\"$(esc "$msg")\""
  post_event status "$json}"
}

cmd_post() {
  [ $# -eq 2 ] || usage
  case "$1" in log|status) ;; *) usage ;; esac
  post_event "$1" "$2"
}

cmd_pipe() {
  while IFS= read -r line; do
    printf '%s\n' "$line" # pass through so it still behaves in a pipeline
    case "$line" in
      "{"*) post_event log "$line" ;;
      *) post_event log "{\"v\":1,\"type\":\"log\",\"ts\":\"$(now)\",\"msg\":\"$(esc "$line")\"}" ;;
    esac
  done
}

case "${1:-}" in
  new) shift; cmd_new "$@" ;;
  log) shift; cmd_log "$@" ;;
  status) shift; cmd_status "$@" ;;
  post) shift; cmd_post "$@" ;;
  pipe) shift; cmd_pipe ;;
  *) usage ;;
esac
