#!/usr/bin/env bash
# Author: Marcel Herrguth, Claude Code
set -euo pipefail

usage() {
  cat <<EOF
Usage: $0 <action> [options]

Actions:
  create-ro   Create a read-only user (and a matching role)
  create-rw   Create a read-write user (and a matching role)
  remove      Remove a single named user (refuses default/reserved users)

Options:
  -u <url>       Elasticsearch URL      (default: https://127.0.0.1:9200)
  -U <user>      Admin username to authenticate with (default: elastic)
  -p <password>  Admin password         (required, or set ES_PASSWORD env var)
  -k             Allow insecure TLS (skip cert verification)
  -n <name>      Username                        (required for all actions)
  -w <password>  New user's password             (required for create-ro / create-rw, or set ES_NEW_PASSWORD)
  -i <pattern>   Restrict access to indices matching "<pattern>*" (default: "*", all indices)

Examples:
  $0 create-ro -U elastic -p "\$ES_PASSWORD" -n zammad_reader -w "\$NEW_PW" -i zammad_production -k
  $0 create-rw -U elastic -p "\$ES_PASSWORD" -n zammad_writer -w "\$NEW_PW" -i zammad_production -k
  $0 remove -U elastic -p "\$ES_PASSWORD" -n zammad_reader -k
EOF
  exit 1
}

[[ $# -ge 1 ]] || usage
action="$1"; shift

url="https://127.0.0.1:9200"
admin_user="elastic"
admin_password="${ES_PASSWORD:-}"
insecure=()
new_user=""
new_password="${ES_NEW_PASSWORD:-}"
index_pattern="*"

while getopts "u:U:p:kn:w:i:h" opt; do
  case "$opt" in
    u) url="$OPTARG" ;;
    U) admin_user="$OPTARG" ;;
    p) admin_password="$OPTARG" ;;
    k) insecure=(--insecure) ;;
    n) new_user="$OPTARG" ;;
    w) new_password="$OPTARG" ;;
    i) index_pattern="${OPTARG}*" ;;
    h|*) usage ;;
  esac
done

[[ -n "$admin_password" ]] || { echo "Admin password required (-p or ES_PASSWORD)"; usage; }

CURL=(curl "${insecure[@]}" -s -u "${admin_user}:${admin_password}")

create_user() {
  local role_name="$1" privileges_json="$2"

  [[ -n "$new_user" ]] || { echo "New username required (-n)"; usage; }
  [[ -n "$new_password" ]] || { echo "New user's password required (-w or ES_NEW_PASSWORD)"; usage; }

  role_body=$(jq -n --argjson privileges "$privileges_json" --arg pattern "$index_pattern" \
    '{indices: [{names: [$pattern], privileges: $privileges}]}')
  role_resp=$("${CURL[@]}" -X PUT "${url}/_security/role/${role_name}" -H 'Content-Type: application/json' -d "$role_body")
  echo "role ${role_name}: $(echo "$role_resp" | jq -c .)"

  user_body=$(jq -n --arg password "$new_password" --arg role "$role_name" \
    '{password: $password, roles: [$role]}')
  user_resp=$("${CURL[@]}" -X PUT "${url}/_security/user/${new_user}" -H 'Content-Type: application/json' -d "$user_body")
  echo "user ${new_user}: $(echo "$user_resp" | jq -c .)"
}

case "$action" in
  create-ro)
    create_user "${new_user}_ro" '["read","view_index_metadata"]'
    echo "Created read-only user '${new_user}', scoped to indices matching '${index_pattern}'."
    ;;

  create-rw)
    create_user "${new_user}_rw" '["read","write","create_index","view_index_metadata"]'
    echo "Created read-write user '${new_user}', scoped to indices matching '${index_pattern}'."
    ;;

  remove)
    [[ -n "$new_user" ]] || { echo "Username required (-n)"; usage; }

    lookup=$("${CURL[@]}" "${url}/_security/user/${new_user}")
    if echo "$lookup" | jq -e 'has("error")' >/dev/null; then
      echo "User '${new_user}' not found."
      exit 1
    fi

    if echo "$lookup" | jq -e --arg u "$new_user" '.[$u].metadata._reserved == true' >/dev/null; then
      echo "'${new_user}' is a default/reserved user — refusing to delete."
      exit 1
    fi

    read -rp "Delete user '${new_user}'? [y/N] " ok
    [[ "$ok" == "y" ]] || exit 1
    "${CURL[@]}" -X DELETE "${url}/_security/user/${new_user}" | jq -c .
    ;;

  *)
    usage
    ;;
esac
