#!/bin/sh
# Creates a management room for a Meowlnir bot, with the given users able to command the bot there.
#
# The room is created by the bot itself, impersonated through the appservice token, so no human account's credentials are needed.
#
# The `trusted_private_chat` preset is what gives the invited users their standing, and it does the right thing on both old and new room versions: on rooms supporting MSC4289 every invitee becomes an additional creator, and on older ones each is given power level 100.
# Either way there is nothing for us to adjust afterwards.
#
# Usage: meowlnir-create-management-room <bot_localpart> <initial_manager_mxid>...
#
# Prints the created room's ID on success.

set -eu

CONFIG_FILE='{{ matrix_bot_meowlnir_config_path }}/config.yaml'
CONTAINER_NAME='matrix-bot-meowlnir'
HOMESERVER_ADDRESS='{{ matrix_bot_meowlnir_config_homeserver_address }}'
HOMESERVER_DOMAIN='{{ matrix_bot_meowlnir_config_homeserver_domain }}'
ROOM_NAME='{{ matrix_bot_meowlnir_management_room_name }}'
ROOM_TOPIC='{{ matrix_bot_meowlnir_management_room_topic | trim }}'
ENCRYPTED='{{ 'true' if matrix_bot_meowlnir_config_encryption_enable else 'false' }}'
REQUEST_TIMEOUT='{{ matrix_bot_meowlnir_api_request_timeout_seconds }}'

if [ $# -lt 2 ]; then
	echo "Usage: $(basename "$0") <bot_localpart> <initial_manager_mxid>..." >&2
	exit 2
fi

bot_localpart="$1"
shift
bot_mxid="@$bot_localpart:$HOMESERVER_DOMAIN"

as_token="$(awk '$1 == "as_token:" { print $2; exit }' "$CONFIG_FILE" | sed 's/^"//; s/"$//')"

if [ -z "$as_token" ]; then
	echo "Could not read as_token from $CONFIG_FILE" >&2
	exit 1
fi

urlencode() {
	printf '%s' "$1" | sed 's/%/%25/g; s/!/%21/g; s/:/%3A/g; s/@/%40/g; s/\$/%24/g; s/\//%2F/g'
}

jq_run() {
	{{ devture_systemd_docker_base_host_command_docker }} exec -i "$CONTAINER_NAME" jq "$@"
}

if [ "$ENCRYPTED" = 'true' ]; then
	initial_state='[{"type": "m.room.encryption", "state_key": "", "content": {"algorithm": "m.megolm.v1.aes-sha2"}}]'
else
	initial_state='[]'
fi

# Matrix user IDs cannot contain newlines, so splitting on them is safe here.
invitees="$(printf '%s\n' "$@" | jq_run -R -s 'split("\n") | map(select(length > 0))')"

create_body="$(jq_run -n \
	--arg name "$ROOM_NAME" \
	--arg topic "$ROOM_TOPIC" \
	--argjson invitees "$invitees" \
	--argjson initial_state "$initial_state" \
	'{preset: "trusted_private_chat", name: $name, topic: $topic, invite: $invitees, initial_state: $initial_state}')"

user_id_param="$(urlencode "$bot_mxid")"

# Runs curl inside the container, because the homeserver is only reachable over the container network.
# Prints the body, with the HTTP status code on the final line.
response="$({{ devture_systemd_docker_base_host_command_docker }} exec "$CONTAINER_NAME" \
	curl -sS --max-time "$REQUEST_TIMEOUT" -X POST \
	-H "Authorization: Bearer $as_token" \
	-H 'Content-Type: application/json' \
	-d "$create_body" \
	-w '\n%{http_code}' \
	"$HOMESERVER_ADDRESS/_matrix/client/v3/createRoom?user_id=$user_id_param")"

status="$(printf '%s\n' "$response" | tail -n 1)"

if [ "$status" != '200' ]; then
	echo "Creating the management room failed with HTTP $status:" >&2
	printf '%s\n' "$response" | sed '$d' >&2
	exit 1
fi

room_id="$(printf '%s\n' "$response" | sed '$d' | jq_run -r '.room_id')"

if [ -z "$room_id" ] || [ "$room_id" = 'null' ]; then
	echo 'The homeserver did not return a room ID' >&2
	exit 1
fi

printf '%s\n' "$room_id"
