#!/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-custom   List and remove all non-default (non-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>      New username                    (required for create-ro / create-rw)
  -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-custom -U elastic -p "\$ES_PASSWORD" -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-custom)
    users=$("${CURL[@]}" "${url}/_security/user" | jq -r 'to_entries[] | select(.value.metadata._reserved != true) | .key')
    if [[ -z "$users" ]]; then
      echo "No non-default users found."
      exit 0
    fi
    echo "Non-default users found:"
    echo "$users" | sed 's/^/  - /'
    read -rp "Delete all of the above? [y/N] " ok
    [[ "$ok" == "y" ]] || exit 1
    for u in $users; do
      "${CURL[@]}" -X DELETE "${url}/_security/user/${u}" | jq -c --arg u "$u" '{user: $u, result: .}'
    done
    ;;

  *)
    usage
    ;;
esac
