#!/usr/bin/env bash

# Copyright © 2023 OpenIM. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# OpenIM RPC Service Test Control Script
#
# This control script is designed to conduct various tests on the OpenIM RPC services.
# It includes functions to perform smoke tests, API tests, and comprehensive service tests.
# The script is intended to be used in a Linux environment with appropriate permissions and
# environmental variables set.
#
# It provides robust error handling and logging to facilitate debugging and service monitoring.
# Functions within the script can be called directly or passed as arguments to perform
# systematic testing, ensuring the integrity of the RPC services.
#
# Test Functions:
# - openim::test::smoke: Runs basic tests to ensure the fundamental functionality of the service.
# - openim::test::api: Executes a series of API tests covering authentication, user, friend,
#   group, and message functionalities.
# - openim::test::test: Performs a complete test suite, invoking utility checks and all defined
#   test cases, and reports on their success.
#

# The root of the build/dist directory
OPENIM_ROOT=$(dirname "${BASH_SOURCE[0]}")/../..
[[ -z ${COMMON_SOURCED} ]] && source ${OPENIM_ROOT}/scripts/install/common.sh

# API Server API Address:Port
INSECURE_OPENIMAPI="http://${OPENIM_API_HOST}:${API_OPENIM_PORT}"
INSECURE_OPENIMAUTO=${OPENIM_RPC_AUTH_HOST}:${OPENIM_AUTH_PORT}
CCURL="curl -f -s -XPOST"   # Create
UCURL="curl -f -s -XPUT"    # Update
RCURL="curl -f -s -XGET"    # Retrieve
DCURL="curl -f -s -XDELETE" # Delete

openim::test::check_error() {
	local response=$1
	local err_code=$(echo "$response" | jq '.errCode')
	openim::log::status "Response from user registration: $response"
	if [[ "$err_code" != "0" ]]; then
		openim::log::error_exit "Error occurred: $response, You can read the error code in the API documentation https://docs.openim.io/restapi/errcode"
	else
		openim::log::success "Operation was successful."
	fi
}

# The `openim::test::auth` function serves as a test suite for authentication-related operations.
function openim::test::auth() {
	# 1. Retrieve and set the authentication token.
	openim::test::get_token

	# 2. Force logout the test user from a specific platform.
	openim::test::force_logout

	# Log the completion of the auth test suite.
	openim::log::success "Auth test suite completed successfully."
}

#################################### Auth Module ####################################

# Define a function to get a token for a specific user
openim::test::get_token() {
	local user_id="${1:-imAdmin}" # Default user ID if not provided
	token_response=$(
		${CCURL} "${OperationID}" "${Header}" ${INSECURE_OPENIMAPI}/auth/user_token \
		-d'{"secret": "'"$SECRET"'","platformID": 1,"userID": "'$user_id'"}'
	)
	token=$(echo $token_response | grep -Po 'token[" :]+\K[^"]+')
	echo "$token"
}

Header="-HContent-Type: application/json"
OperationID="-HoperationID: 1646445464564"
Token="-Htoken: $(openim::test::get_token)"

# Forces a user to log out from the specified platform by user ID.
openim::test::force_logout() {
	local request_body=$(
		cat <<EOF
{
  "platformID": 2,
  "userID": "4950983283"
}
EOF
	)
	echo "Requesting force logout for user: $request_body"

	local response=$(${CCURL} "${Token}" "${OperationID}" "${Header}" "${INSECURE_OPENIMAPI}/auth/force_logout" -d "${request_body}")

	openim::test::check_error "$response"
}

#################################### User Module ####################################

# Registers a new user with provided user ID, nickname, and face URL using the API.
openim::test::user_register() {
	# Assign the parameters to local variables, with defaults if not provided
	local user_id="${1:-${TEST_USER_ID}}"
	local nickname="${2:-cubxxw}"
	local face_url="${3:-https://github.com/cubxxw}"

	# Create the request body using the provided or default values
	local request_body=$(
		cat <<EOF
{
  "secret": "${SECRET}",
  "users": [
    {
      "userID": "${user_id}",
      "nickname": "${nickname}",
      "faceURL": "${face_url}"
    }
  ]
}
EOF
	)

	echo "Request body for user registration: $request_body"

	# Send the registration request
	local user_register_response=$(${CCURL} "${OperationID}" "${Header}" "${INSECURE_OPENIMAPI}/user/user_register" -d "${request_body}")

	# Check for errors in the response
	openim::test::check_error "$user_register_response"
}

# Checks if the provided list of user IDs exist in the system.
openim::test::check_user_account() {
	local request_body=$(
		cat <<EOF
{
  "checkUserIDs": [
    "${1}"
  ]
}
EOF
	)
	echo "$request_body"

	local response=$(${CCURL} "${Token}" "${OperationID}" "${Header}" "${INSECURE_OPENIMAPI}/user/account_check" -d "${request_body}")

	openim::test::check_error "$response"
}

# Retrieves a list of users with pagination, limited to a specific number per page.
openim::test::get_users() {
	local request_body=$(
		cat <<EOF
{
  "pagination": {
    "pageNumber": 1,
    "showNumber": 100
  }
}
EOF
	)
	echo "$request_body"

	local response=$(${CCURL} "${Token}" "${OperationID}" "${Header}" "${INSECURE_OPENIMAPI}/user/get_users" -d "${request_body}")

	openim::test::check_error "$response"
}

# Obtains detailed information for a list of user IDs.
openim::test::get_users_info() {
	local request_body=$(
		cat <<EOF
{
  "userIDs": [
    "${1}"
  ]
}
EOF
	)
	echo "$request_body"

	local response=$(${CCURL} "${Token}" "${OperationID}" "${Header}" "${INSECURE_OPENIMAPI}/user/get_users_info" -d "${request_body}")

	openim::test::check_error "$response"
}

# Retrieves the online status for a list of user IDs.
openim::test::get_users_online_status() {
	local request_body=$(
		cat <<EOF
{
  "userIDs": [
    "${TEST_USER_ID}"
  ]
}
EOF
	)
	echo "$request_body"

	local response=$(${CCURL} "${Token}" "${OperationID}" "${Header}" "${INSECURE_OPENIMAPI}/user/get_users_online_status" -d "${request_body}")

	openim::test::check_error "$response"
}

# Updates the information for a user, such as nickname and face URL.
openim::test::update_user_info() {
	local request_body=$(
		cat <<EOF
{
  "userInfo": {
    "userID": "${TEST_USER_ID}",
    "nickname": "openimbot",
    "faceURL": "https://github.com/openimbot"
  }
}
EOF
	)
	echo "$request_body"

	local response=$(${CCURL} "${Token}" "${OperationID}" "${Header}" "${INSECURE_OPENIMAPI}/user/update_user_info" -d "${request_body}")

	openim::test::check_error "$response"
}

# Gets the online status for users that a particular user has subscribed to.
openim::test::get_subscribe_users_status() {
	local request_body=$(
		cat <<EOF
{
  "userID": "${TEST_USER_ID}"
}
EOF
	)
	echo "$request_body"

	local response=$(${CCURL} "${Token}" "${OperationID}" "${Header}" "${INSECURE_OPENIMAPI}/user/get_subscribe_users_status" -d "${request_body}")

	openim::test::check_error "$response"
}

# Subscribes to the online status of a list of users for a particular user ID.
openim::test::subscribe_users_status() {
	local request_body=$(
		cat <<EOF
{
  "userID": "9168684795",
  "userIDs": [
    "7475779354",
    "6317136453",
    "8450535746"
  ],
  "genre": 1
}
EOF
	)
	echo "$request_body"

	local response=$(${CCURL} "${Token}" "${OperationID}" "${Header}" "${INSECURE_OPENIMAPI}/user/subscribe_users_status" -d "${request_body}")

	openim::test::check_error "$response"
}

# Sets the global message receiving option for a user, determining their messaging preferences.
openim::test::set_global_msg_recv_opt() {
	local request_body=$(
		cat <<EOF
{
  "userID": "${TEST_USER_ID}",
  "globalRecvMsgOpt": 0
}
EOF
	)
	echo "$request_body"

	local response=$(${CCURL} "${Token}" "${OperationID}" "${Header}" "${INSECURE_OPENIMAPI}/user/set_global_msg_recv_opt" -d "${request_body}")

	openim::test::check_error "$response"
}

# [openim::test::user function description]
# The `openim::test::user` function serves as a test suite for user-related operations.
# It sequentially invokes all user-related test functions to ensure the API's user operations are functioning correctly.
function openim::test::user() {
	# 1. Register a test user.
	local USER_ID=$RANDOM
	local TEST_USER_ID=$RANDOM
	openim::test::user_register "${USER_ID}" "user01" "new_face_url"
	openim::test::user_register "${TEST_USER_ID}" "user01" "new_face_url"
	# 2. Check if the test user's account exists.
	openim::test::check_user_account "${TEST_USER_ID}"

	# 3. Retrieve a list of users.
	openim::test::get_users

	# 4. Get detailed information for the test user.
	openim::test::get_users_info "${TEST_USER_ID}"

	# 5. Check the online status of the test user.
	openim::test::get_users_online_status

	# 6. Update the test user's information.
	openim::test::update_user_info

	# 7. Get the status of users subscribed by the test user.
	openim::test::get_subscribe_users_status

	# 8. Subscribe the test user to a set of user statuses.
	openim::test::subscribe_users_status

	# 9. Set the message receiving option for the test user.
	openim::test::set_global_msg_recv_opt

	# Log the completion of the user test suite.
	openim::log::success "User test suite completed successfully."
}

#################################### Friend Module ####################################

# Checks if two users are friends.
openim::test::is_friend() {
	local request_body=$(
		cat <<EOF
{
  "userID1": "${1}",
  "userID2": "${2}"
}
EOF
	)
	echo "$request_body"

	local response=$(${CCURL} "${Token}" "${OperationID}" "${Header}" "${INSECURE_OPENIMAPI}/friend/is_friend" -d "${request_body}")

	openim::test::check_error "$response"
}

# Deletes a friend for a user.
openim::test::delete_friend() {
	local request_body=$(
		cat <<EOF
{
  "ownerUserID":"${1}",
  "friendUserID":"${2}"
}
EOF
	)
	echo "$request_body"

	local response=$(${CCURL} "${Token}" "${OperationID}" "${Header}" "${INSECURE_OPENIMAPI}/friend/delete_friend" -d "${request_body}")

	openim::test::check_error "$response"
}

# Gets the friend application list for a user.
openim::test::get_friend_apply_list() {
	local request_body=$(
		cat <<EOF
{
  "userID": "${IM_ADMIN_USERID}",
  "pagination": {
    "pageNumber": 1,
    "showNumber": 100
  }
}
EOF
	)
	echo "$request_body"

	local response=$(${CCURL} "${Token}" "${OperationID}" "${Header}" "${INSECURE_OPENIMAPI}/friend/get_friend_apply_list" -d "${request_body}")

	openim::test::check_error "$response"
}

# Gets the friend list for a user.
openim::test::get_friend_list() {
	local request_body=$(
		cat <<EOF
{
  "userID": "${1}",
  "pagination": {
    "pageNumber": 1,
    "showNumber": 100
  }
}
EOF
	)
	echo "$request_body"

	local response=$(${CCURL} "${Token}" "${OperationID}" "${Header}" "${INSECURE_OPENIMAPI}/friend/get_friend_list" -d "${request_body}")

	openim::test::check_error "$response"
}

# Sets a remark for a friend.
openim::test::set_friend_remark() {
	local request_body=$(
		cat <<EOF
{
  "ownerUserID": "${1}",
  "friendUserID": "${2}",
  "remark": "remark"
}
EOF
	)
	echo "$request_body"

	local response=$(${CCURL} "${Token}" "${OperationID}" "${Header}" "${INSECURE_OPENIMAPI}/friend/set_friend_remark" -d "${request_body}")

	openim::test::check_error "$response"
}

# Adds a friend request.
openim::test::add_friend() {
	local request_body=$(
		cat <<EOF
{
  "fromUserID": "${1}",
  "toUserID": "${2}",
  "reqMsg": "hello!",
  "ex": ""
}
EOF
	)
	echo "$request_body"

	local response=$(${CCURL} "${Token}" "${OperationID}" "${Header}" "${INSECURE_OPENIMAPI}/friend/add_friend" -d "${request_body}")

	openim::test::check_error "$response"
}

# Imports friends for a user.
openim::test::import_friend() {
	local friend_ids=$(printf ', "%s"' "${@:2}")
	friend_ids=${friend_ids:2}
	local request_body=$(
		cat <<EOF
{
  "ownerUserID": "${1}",
  "friendUserIDs": [${friend_ids}]
}
EOF
	)
	echo "$request_body"

	local response=$(${CCURL} "${Token}" "${OperationID}" "${Header}" "${INSECURE_OPENIMAPI}/friend/import_friend" -d "${request_body}")

	openim::test::check_error "$response"
}

# Responds to a friend request.
openim::test::add_friend_response() {
	local request_body=$(
		cat <<EOF
{
  "fromUserID": "${1}",
  "toUserID": "${2}",
  "handleResult": 1,
  "handleMsg": "agree"
}
EOF
	)
	echo "$request_body"

	local response=$(${CCURL} "${Token}" "${OperationID}" "${Header}" "${INSECURE_OPENIMAPI}/friend/add_friend_response" -d "${request_body}")

	openim::test::check_error "$response"
}

# Retrieves the friend application list that the user has applied for.
openim::test::get_self_friend_apply_list() {
	local request_body=$(
		cat <<EOF
{
  "userID": "${1}",
  "pagination": {
    "pageNumber": ${2},
    "showNumber": ${3}
  }
}
EOF
	)
	echo "$request_body"

	local response=$(${CCURL} "${Token}" "${OperationID}" "${Header}" "${INSECURE_OPENIMAPI}/friend/get_self_friend_apply_list" -d "${request_body}")

	openim::test::check_error "$response"
}

# Adds a user to the blacklist.
openim::test::add_black() {
	local request_body=$(
		cat <<EOF
{
  "ownerUserID": "${1}",
  "blackUserID": "${2}"
}
EOF
	)
	echo "$request_body"

	local response=$(${CCURL} "${Token}" "${OperationID}" "${Header}" "${INSECURE_OPENIMAPI}/friend/add_black" -d "${request_body}")

	openim::test::check_error "$response"
}

# Removes a user from the blacklist.
openim::test::remove_black() {
	local request_body=$(
		cat <<EOF
{
  "ownerUserID": "${1}",
  "blackUserID": "${2}"
}
EOF
	)
	echo "$request_body"

	local response=$(${CCURL} "${Token}" "${OperationID}" "${Header}" "${INSECURE_OPENIMAPI}/friend/remove_black" -d "${request_body}")

	openim::test::check_error "$response"
}

# Retrieves the blacklist for a user.
openim::test::get_black_list() {
	local request_body=$(
		cat <<EOF
{
  "userID": "${1}",
  "pagination": {
    "pageNumber": 1,
    "showNumber": 100
  }
}
EOF
	)
	echo "$request_body"

	local response=$(${CCURL} "${Token}" "${OperationID}" "${Header}" "${INSECURE_OPENIMAPI}/friend/get_black_list" -d "${request_body}")

	openim::test::check_error "$response"
}

# Updates the pin status of multiple friends.
openim::test::update_pin_status() {
	local ownerUserID="${1}"
	shift # Shift the arguments to skip the first one (ownerUserID)
	local isPinned="${1}"
	shift # Shift the arguments to skip the isPinned argument

	# Constructing the list of friendUserIDs
	local friendUserIDsArray=()
	for friendUserID in "$@"; do
		friendUserIDsArray+=("\"${friendUserID}\"")
	done
	local friendUserIDs=$(
		IFS=,
		echo "${friendUserIDsArray[*]}"
	)

	local request_body=$(
		cat <<EOF
{
  "ownerUserID": "${ownerUserID}",
  "friendUserIDs": [${friendUserIDs}],
  "isPinned": ${isPinned}
}
EOF
	)
	echo "Requesting to update pin status: $request_body"

	local response=$(${CCURL} "${Token}" "${OperationID}" "${Header}" "${INSECURE_OPENIMAPI}/friend/update_pin_status" -d "${request_body}")
	echo "Response: $response"
	openim::test::check_error "$response"
}

# [openim::test::friend function description]
# The `openim::test::friend` function serves as a test suite for friend-related operations.
# It sequentially invokes all friend-related test functions to ensure the API's friend operations are functioning correctly.
function openim::test::friend() {
	local FRIEND_USER_ID=$RANDOM
	local BLACK_USER_ID=$RANDOM
	local TEST_USER_ID=$RANDOM
	# Assumes that TEST_USER_ID, FRIEND_USER_ID, and other necessary IDs are set as environment variables before running this suite.
	# 0. Register a friend user.
	openim::test::user_register "${TEST_USER_ID}" "user01" "new_face_url"
	openim::test::user_register "${FRIEND_USER_ID}" "frient01" "new_face_url"
	openim::test::user_register "${BLACK_USER_ID}" "frient02" "new_face_url"

	# 1. Check if two users are friends.
	openim::test::is_friend "${TEST_USER_ID}" "${FRIEND_USER_ID}"

	# 2. Send a friend request from one user to another.
	openim::test::add_friend "${TEST_USER_ID}" "${FRIEND_USER_ID}"

	local original_token=$Token

	# Switch to FRIEND_USER_ID's token
	local friend_token="-Htoken: $(openim::test::get_token "${FRIEND_USER_ID}")"
	# 3. Respond to a friend request.
	# TODO:
	# openim::test::add_friend_response "${FRIEND_USER_ID}" "${TEST_USER_ID}"

	Token=$original_token
	# 4. Retrieve the friend list of the test user.
	openim::test::get_friend_list "${TEST_USER_ID}"

	# 5. Set a remark for a friend.
	# TODO:
	# openim::test::set_friend_remark "${TEST_USER_ID}" "${FRIEND_USER_ID}"

	# 6. Retrieve the friend application list for the test user.
	openim::test::get_friend_apply_list "${TEST_USER_ID}" 1 100

	# 7. Retrieve the friend application list that the user has applied for.
	openim::test::get_self_friend_apply_list "${TEST_USER_ID}" 1 100

	# 8. Delete a friend.
	# TODO:
	# openim::test::delete_friend "${TEST_USER_ID}" "${FRIEND_USER_ID}"

	# 9. Add a user to the blacklist.
	openim::test::add_black "${TEST_USER_ID}" "${BLACK_USER_ID}"

	# 10. Remove a user from the blacklist.
	openim::test::remove_black "${TEST_USER_ID}" "${BLACK_USER_ID}"

	# 11. Retrieve the blacklist for the test user.
	openim::test::get_black_list "${TEST_USER_ID}"

	# 12. Import friends for the user (Optional).
	# TODO:
	#   openim::test::import_friend "${TEST_USER_ID}" "11111114" "11111115"

	# 13. pin Friend
	# Add this call to your test suite where appropriate
	# TODO:
	#  openim::test::update_pin_status "${TEST_USER_ID}" true "${FRIEND_USER_ID}"
	#
	#  openim::test::update_pin_status "${TEST_USER_ID}" false "${FRIEND_USER_ID}"

	# Log the completion of the friend test suite.
	openim::log::success "Friend test suite completed successfully."
}

#################################### Group Module ####################################

# Creates a new group.
openim::test::create_group() {
	local request_body=$(
		cat <<EOF
{
  "memberUserIDs": [
    "${1}"
  ],
  "adminUserIDs": [
    "${2}"
  ],
  "ownerUserID": "${3}",
  "groupInfo": {
    "groupID": "${4}",
    "groupName": "test-group",
    "notification": "notification",
    "introduction": "introduction",
    "faceURL": "faceURL url",
    "ex": "ex",
    "groupType": 2,
    "needVerification": 0,
    "lookMemberInfo": 0,
    "applyMemberFriend": 0
  }
}
EOF
	)
	echo "$request_body"

	local response=$(${CCURL} "${Token}" "${OperationID}" "${Header}" "${INSECURE_OPENIMAPI}/group/create_group" -d "${request_body}")

	openim::test::check_error "$response"
}

# Invites a user to join a group.
openim::test::invite_user_to_group() {
	local request_body=$(
		cat <<EOF
{
  "groupID": "${1}",
  "invitedUserIDs": [
    "${2}",
    "${3}"
  ],
  "reason": "your reason"
}
EOF
	)
	echo "$request_body"

	local response=$(${CCURL} "${Token}" "${OperationID}" "${Header}" "${INSECURE_OPENIMAPI}/group/invite_user_to_group" -d "${request_body}")

	openim::test::check_error "$response"
}

# Transfers the ownership of a group to another user.
openim::test::transfer_group() {
	local request_body=$(
		cat <<EOF
{
  "groupID":"${1}",
  "oldOwnerUserID":"${2}",
  "newOwnerUserID": "${3}"
}
EOF
	)
	echo "$request_body"

	local response=$(${CCURL} "${Token}" "${OperationID}" "${Header}" "${INSECURE_OPENIMAPI}/group/transfer_group" -d "${request_body}")

	openim::test::check_error "$response"
}

# Retrieves information about multiple groups.
openim::test::get_groups_info() {
	local request_body=$(
		cat <<EOF
{
  "groupIDs": ["${1}", "${2}"]
}
EOF
	)
	echo "$request_body"

	local response=$(${CCURL} "${Token}" "${OperationID}" "${Header}" "${INSECURE_OPENIMAPI}/group/get_groups_info" -d "${request_body}")

	openim::test::check_error "$response"
}

# Removes a user from a group.
openim::test::kick_group() {
	local request_body=$(
		cat <<EOF
{
  "groupID": "${1}",
  "kickedUserIDs": [
    "${2}"
  ],
  "reason": "Bye!"
}
EOF
	)
	echo "$request_body"

	local response=$(${CCURL} "${Token}" "${OperationID}" "${Header}" "${INSECURE_OPENIMAPI}/group/kick_group" -d "${request_body}")

	openim::test::check_error "$response"
}

# Retrieves information about group members.
openim::test::get_group_members_info() {
	local request_body=$(
		cat <<EOF
{
  "groupID": "${1}",
  "userIDs": ["${2}"]
}
EOF
	)
	echo "$request_body"

	local response=$(${CCURL} "${Token}" "${OperationID}" "${Header}" "${INSECURE_OPENIMAPI}/group/get_group_members_info" -d "${request_body}")

	openim::test::check_error "$response"
}

# Retrieves a list of group members.
openim::test::get_group_member_list() {
	local request_body=$(
		cat <<EOF
{
  "groupID": "${1}",
  "pagination": {
    "pageNumber": ${2},
    "showNumber": ${3}
  }
}
EOF
	)
	echo "$request_body"

	local response=$(${CCURL} "${Token}" "${OperationID}" "${Header}" "${INSECURE_OPENIMAPI}/group/get_group_member_list" -d "${request_body}")

	openim::test::check_error "$response"
}

# Retrieves a list of groups that a user has joined.
openim::test::get_joined_group_list() {
	local request_body=$(
		cat <<EOF
{
  "fromUserID": "${1}",
  "pagination": {
    "showNumber": ${2},
    "pageNumber": ${3}
  }
}
EOF
	)
	echo "$request_body"

	local response=$(${CCURL} "${Token}" "${OperationID}" "${Header}" "${INSECURE_OPENIMAPI}/group/get_joined_group_list" -d "${request_body}")

	openim::test::check_error "$response"
}

# Sets group member information.
openim::test::set_group_member_info() {
	local request_body=$(
		cat <<EOF
{
  "members": [
    {
      "groupID": "${1}",
      "userID": "${2}",
      "nickName": "${3}",
      "faceURL": "${4}",
      "roleLevel": ${5},
      "ex":"${6}"
    }
  ]
}
EOF
	)
	echo "$request_body"

	local response=$(${CCURL} "${Token}" "${OperationID}" "${Header}" "${INSECURE_OPENIMAPI}/group/set_group_member_info" -d "${request_body}")

	openim::test::check_error "$response"
}

# Mutes a group.
openim::test::mute_group() {
	local request_body=$(
		cat <<EOF
{
  "groupID": "${1}"
}
EOF
	)
	echo "$request_body"

	local response=$(${CCURL} "${Token}" "${OperationID}" "${Header}" "${INSECURE_OPENIMAPI}/group/mute_group" -d "${request_body}")

	openim::test::check_error "$response"
}

# Cancels the muting of a group.
openim::test::cancel_mute_group() {
	local request_body=$(
		cat <<EOF
{
  "groupID": "${1}"
}
EOF
	)
	echo "$request_body"

	local response=$(${CCURL} "${Token}" "${OperationID}" "${Header}" "${INSECURE_OPENIMAPI}/group/cancel_mute_group" -d "${request_body}")

	openim::test::check_error "$response"
}

# Dismisses a group.
openim::test::dismiss_group() {
	local request_body=$(
		cat <<EOF
{
  "groupID":"${1}"
}
EOF
	)
	echo "$request_body"

	local response=$(${CCURL} "${Token}" "${OperationID}" "${Header}" "${INSECURE_OPENIMAPI}/group/dismiss_group" -d "${request_body}")

	openim::test::check_error "$response"
}

# Cancels muting a group member.
openim::test::cancel_mute_group_member() {
	local request_body=$(
		cat <<EOF
{
  "groupID": "${1}",
  "userID": "${2}"
}
EOF
	)
	echo "$request_body"

	local response=$(${CCURL} "${Token}" "${OperationID}" "${Header}" "${INSECURE_OPENIMAPI}/group/cancel_mute_group_member" -d "${request_body}")

	openim::test::check_error "$response"
}

# Allows a user to join a group.
openim::test::join_group() {
	local request_body=$(
		cat <<EOF
{
 "groupID": "${1}",
 "reqMessage": "req msg join group",
 "joinSource": 0,
 "inviterUserID": "${2}"
}
EOF
	)
	echo "$request_body"

	local response=$(${CCURL} "${Token}" "${OperationID}" "${Header}" "${INSECURE_OPENIMAPI}/group/join_group" -d "${request_body}")

	openim::test::check_error "$response"
}

# Sets group information.
openim::test::set_group_info() {
	local request_body=$(
		cat <<EOF
{
  "groupInfoForSet": {
    "groupID": "${1}",
    "groupName": "new-name",
    "notification": "new notification",
    "introduction": "new introduction",
    "faceURL": "www.newfaceURL.com",
    "ex": "new ex",
    "needVerification": 1,
    "lookMemberInfo": 1,
    "applyMemberFriend": 1
  }
}
EOF
	)
	echo "$request_body"

	local response=$(${CCURL} "${Token}" "${OperationID}" "${Header}" "${INSECURE_OPENIMAPI}/group/set_group_info" -d "${request_body}")

	openim::test::check_error "$response"
}

# Allows a user to quit a group.
openim::test::quit_group() {
	local request_body=$(
		cat <<EOF
{
  "groupID": "${1}",
  "userID": "${2}"
}
EOF
	)
	echo "$request_body"

	local response=$(${CCURL} "${Token}" "${OperationID}" "${Header}" "${INSECURE_OPENIMAPI}/group/quit_group" -d "${request_body}")

	openim::test::check_error "$response"
}

# Retrieves the list of group applications received by the user.
openim::test::get_recv_group_applicationList() {
	local request_body=$(
		cat <<EOF
{
  "fromUserID": "${1}",
  "pagination": {
    "pageNumber": ${2},
    "showNumber": ${3}
  }
}
EOF
	)
	echo "$request_body"

	local response=$(${CCURL} "${Token}" "${OperationID}" "${Header}" "${INSECURE_OPENIMAPI}/group/get_recv_group_applicationList" -d "${request_body}")

	openim::test::check_error "$response"
}

# Responds to a group application.
openim::test::group_application_response() {
	local request_body=$(
		cat <<EOF
{
  "groupID": "${1}",
  "fromUserID": "${2}",
  "handledMsg": "",
  "handleResult": 1
}
EOF
	)
	echo "$request_body"

	local response=$(${CCURL} "${Token}" "${OperationID}" "${Header}" "${INSECURE_OPENIMAPI}/group/group_application_response" -d "${request_body}")

	openim::test::check_error "$response"
}

# Retrieves the list of group applications made by the user.
openim::test::get_user_req_group_applicationList() {
	local request_body=$(
		cat <<EOF
{
  "userID": "${1}",
  "pagination": {
    "pageNumber": ${2},
    "showNumber": ${3}
  }
}
EOF
	)
	echo "$request_body"

	local response=$(${CCURL} "${Token}" "${OperationID}" "${Header}" "${INSECURE_OPENIMAPI}/group/get_user_req_group_applicationList" -d "${request_body}")

	openim::test::check_error "$response"
}

# Mutes a group member for a specified duration.
openim::test::mute_group_member() {
	local request_body=$(
		cat <<EOF
{
  "groupID": "${1}",
  "userID": "${2}",
  "mutedSeconds": ${3}
}
EOF
	)
	echo "$request_body"

	local response=$(${CCURL} "${Token}" "${OperationID}" "${Header}" "${INSECURE_OPENIMAPI}/group/mute_group_member" -d "${request_body}")

	openim::test::check_error "$response"
}

# Retrieves a list of group applications from specific users.
openim::test::get_group_users_req_application_list() {
	local request_body=$(
		cat <<EOF
{
  "groupID": "${1}",
  "userIDs": [
    "${2}"
  ]
}
EOF
	)
	echo "$request_body"

	local response=$(${CCURL} "${Token}" "${OperationID}" "${Header}" "${INSECURE_OPENIMAPI}/group/get_group_users_req_application_list" -d "${request_body}")

	openim::test::check_error "$response"
}

# [openim::test::group function description]
# The `openim::test::group` function serves as a test suite for group-related operations.
# It sequentially invokes all group-related test functions to ensure the API's group operations are functioning correctly.
function openim::test::group() {
	local USER_ID=$RANDOM
	local OTHER_USER1_ID=$RANDOM
	local OTHER_USER2_ID=$RANDOM
    local OTHER_USER3_ID=$RANDOM
	local TEST_USER_ID=$RANDOM

	local GROUP_ID=$RANDOM
	local GROUP_ID2=$RANDOM
	# Assumes that TEST_GROUP_ID, USER_ID, and other necessary IDs are set as environment variables before running this suite.
	# 0. Register a friend user.
	openim::test::user_register "${USER_ID}" "group00" "new_face_url"
	openim::test::user_register "${OTHER_USER1_ID}" "group01" "new_face_url"
	openim::test::user_register "${OTHER_USER2_ID}" "group02" "new_face_url"
    openim::test::user_register "${OTHER_USER3_ID}" "group03" "new_face_url"

	# 0. Create a new group.
	openim::test::create_group "$OTHER_USER2_ID" "$OTHER_USER1_ID" "$USER_ID" "$GROUP_ID"

	# 1. Invite user to group.
	openim::test::invite_user_to_group "$GROUP_ID" "$IM_ADMIN_USERID" "$OTHER_USER3_ID"

	# 2. Transfer group ownership.
	openim::test::transfer_group "$GROUP_ID" "$USER_ID" "$OTHER_USER1_ID"

	# 3. Get group information.
	openim::test::get_groups_info "$GROUP_ID" "$OTHER_USER1_ID"

	# 4. Kick a user from the group.
    # TODO 
	# openim::test::kick_group "$GROUP_ID" "$OTHER_USER2_ID"

	# 5. Get group members info.
	openim::test::get_group_members_info "$GROUP_ID" "$USER_ID"

	# 6. Get group member list.
	openim::test::get_group_member_list "$GROUP_ID" 1 100

	# 7. Get joined group list.
	openim::test::get_joined_group_list "$USER_ID" 10 1

	# 8. Set group member info.
	openim::test::set_group_member_info "$GROUP_ID" "$USER_ID" "New NickName" "New Face URL" 60 "Extra Info"

	# 9. Mute group.
	openim::test::mute_group "$GROUP_ID"

	# 10. Cancel mute group.
	openim::test::cancel_mute_group "$GROUP_ID"

	# 11. Dismiss group.
	openim::test::dismiss_group "$GROUP_ID"

	openim::test::create_group "$OTHER_USER2_ID" "$OTHER_USER1_ID" "$USER_ID" "$GROUP_ID2"

	# 12. Cancel mute group member.
	openim::test::cancel_mute_group_member "$GROUP_ID" "$USER_ID"

	# 13. Join group.
	# TODO:
	#   openim::test::join_group "$GROUP_ID2" "$OTHER_USER2_ID"

	# 14. Set group info.
	openim::test::set_group_info "$GROUP_ID2"

	# 15. Quit group.
    # TODO 
	# openim::test::quit_group "$GROUP_ID2" "$OTHER_USER1_ID"

	# 16. Get received group application list.
	openim::test::get_recv_group_applicationList "$USER_ID" 1 100

	# 17. Group application response.
	# TODO:
	#   openim::test::group_application_response "$GROUP_ID2" "$OTHER_USER2_ID"

	# 18. Get user requested group application list.
	openim::test::get_user_req_group_applicationList "$USER_ID" 1 100

	# 19. Mute group member.
	openim::test::mute_group_member "$GROUP_ID" "$OTHER_USER1_ID" 3600

	# 20. Get group users request application list.
	openim::test::get_group_users_req_application_list "$GROUP_ID" "$USER_ID"

	# Log the completion of the group test suite.
	openim::log::success "Group test suite completed successfully."
}

#################################### Register And Check Module ####################################

# Define a function to register a user
openim::register_user() {
	user_register_response=$(
		${CCURL} "${Header}" ${INSECURE_OPENIMAPI}/user/user_register \
		-d'{
"secret": "openIM123",
"users": [{"userID": "11111112","nickname": "yourNickname","faceURL": "yourFaceURL"}]
}'
	)

	echo "$user_register_response"
}

# Define a function to check the account
openim::test::check_account() {
	local token=$1
	account_check_response=$(
		${CCURL} "${Header}" -H"operationID: 1646445464564" -H"token: ${token}" ${INSECURE_OPENIMAPI}/user/account_check \
		-d'{
"checkUserIDs": ["11111111","11111112"]
}'
	)

	echo "$account_check_response"
}

# Define a function to register, get a token and check the account
openim::test::register_and_check() {
	# Register a user
	user_register_response=$(openim::register_user)

	if [[ "$user_register_response" == *"\"errCode\": 0"* ]]; then
		echo "User registration successful."

		# Get token
		token=$(openim::test::get_token)

		if [[ -n "$token" ]]; then
			echo "Token acquired: $token"

			# Check account
			account_check_response=$(openim::check_account "$token")

			if [[ "$account_check_response" == *"\"errCode\": 0"* ]]; then
				echo "Account check successful."
			else
				echo "Account check failed."
			fi
		else
			echo "Failed to acquire token."
		fi
	else
		echo "User registration failed."
	fi
}

#################################### Msg Module ####################################

# Sends a message.
openim::test::send_msg() {
	local sendID="${1}"
	local recvID="${2}"
	local groupID="${3}"

	local request_body=$(
		cat <<EOF
{
  "sendID": "${sendID}",
  "recvID": "${recvID}",
  "groupID": "${groupID}",
  "senderNickname": "openIMAdmin-Gordon",
  "senderFaceURL": "http://www.head.com",
  "senderPlatformID": 1,
  "content": {
    "content": "hello!!"
  },
  "contentType": 101,
  "sessionType": 1,
  "isOnlineOnly": false,
  "notOfflinePush": false,
  "sendTime": $(date +%s)000,
  "offlinePushInfo": {
    "title": "send message",
    "desc": "",
    "ex": "",
    "iOSPushSound": "default",
    "iOSBadgeCount": true
  }
}
EOF
	)
	echo "$request_body"

	local response=$(${CCURL} "${Token}" "${OperationID}" "${Header}" "${INSECURE_OPENIMAPI}/msg/send_msg" -d "${request_body}")

	openim::test::check_error "$response"
}

# Searches for messages.
openim::test::search_msg() {
	local sendID="${1}"
	local recvID="${2}"
	local msgType="${3}"
	local sendTime="${4}"
	local sessionType="${5}"
	local pageNumber="${6}"
	local showNumber="${7}"

	# Construct the request body
	local request_body=$(
		cat <<EOF
{
  "sendID": "${sendID}",
  "recvID": "${recvID}",
  "msgType": ${msgType},
  "sendTime": "${sendTime}",
  "sessionType": ${sessionType},
  "pagination": {
    "pageNumber": ${pageNumber},
    "showNumber": ${showNumber}
  }
}
EOF
	)
	echo "$request_body"

	# Send the request
	local response=$(${CCURL} "${Token}" "${OperationID}" "${Header}" "${INSECURE_OPENIMAPI}/msg/search_msg" -d "${request_body}")

	# Check the response for errors
	openim::test::check_error "$response"
}

# Pulls messages by sequence.
openim::test::pull_msg_by_seq() {
	local userID="${1}"
	local conversationID="${2}"
	local beginSeq="${3}"
	local endSeq="${4}"
	local num="${5}"
	local order="${6}" # Assuming 0 for ascending, 1 for descending

	# Construct the request body
	local request_body=$(
		cat <<EOF
{
  "userID": "${userID}",
  "seqRanges": [
    {
      "conversationID": "${conversationID}",
      "begin": ${beginSeq},
      "end": ${endSeq},
      "num": ${num}
    }
  ],
  "order": ${order}
}
EOF
	)
	echo "$request_body"

	# Send the request
	local response=$(${CCURL} "${Token}" "${OperationID}" "${Header}" "${INSECURE_OPENIMAPI}/msg/pull_msg_by_seq" -d "${request_body}")

	# Check the response for errors
	openim::test::check_error "$response"
}

# Revokes a message.
openim::test::revoke_msg() {
	local userID="${1}"
	local conversationID="${2}"
	local seq="${3}"

	local request_body=$(
		cat <<EOF
{
  "userID": "${userID}",
  "conversationID": "${conversationID}",
  "seq": ${seq}
}
EOF
	)
	echo "$request_body"

	local response=$(${CCURL} "${Token}" "${OperationID}" "${Header}" "${INSECURE_OPENIMAPI}/msg/revoke_msg" -d "${request_body}")

	openim::test::check_error "$response"
}

# Clears all messages for a user.
openim::test::user_clear_all_msg() {
	local userID="${1}"

	local request_body=$(
		cat <<EOF
{
  "userID": "${userID}"
}
EOF
	)
	echo "$request_body"

	local response=$(${CCURL} "${Token}" "${OperationID}" "${Header}" "${INSECURE_OPENIMAPI}/msg/user_clear_all_msg" -d "${request_body}")

	openim::test::check_error "$response"
}

# [openim::test::msg function description]
# The `openim::test::msg` function serves as a test suite for message-related operations.
# It sequentially invokes all message-related test functions to ensure the API's message operations are functioning correctly.
function openim::test::msg() {
	local SEND_USER_ID="${IM_ADMIN_USERID}" # This should be the sender's userID
	local GROUP_ID=""                        # GroupID if it's a group message
	local USER_ID="$RANDOM"
	openim::test::user_register "${USER_ID}" "msg00" "new_face_url"
	local RECV_USER_ID="${USER_ID}" # Receiver's userID

	# 0. Send a message.
	openim::test::send_msg "${SEND_USER_ID}" "${RECV_USER_ID}" "${GROUP_ID}"

	# Wait for a short duration to ensure message is sent
	# 1. Search for the message
	local SEARCH_TIME="2023-01-01T00:00:00Z" # You may need to adjust this
	local MSG_TYPE=101
	local SESSION_TYPE=1
	local PAGE_NUMBER=1
	local SHOW_NUMBER=20

	echo "Searching for messages between ${SEND_USER_ID} and ${RECV_USER_ID}..."
	openim::test::search_msg "${IM_ADMIN_USERID}" "${RECV_USER_ID}" "${MSG_TYPE}" "${SEARCH_TIME}" "${SESSION_TYPE}" "${PAGE_NUMBER}" "${SHOW_NUMBER}"

	# 3. Pull messages by sequence.
	local CONVERSATION_ID="ci_${SEND_USER_ID}_${RECV_USER_ID}" # Adjust as per your conversation ID format
	local BEGIN_SEQ=0
	local END_SEQ=10
	local NUM=5
	local ORDER=0 # Assuming 0 for ascending order
	openim::test::pull_msg_by_seq "${RECV_USER_ID}" "${CONVERSATION_ID}" "${BEGIN_SEQ}" "${END_SEQ}" "${NUM}" "${ORDER}"

	# Assuming message sending was successful and returned a sequence number.
	local SEQ_NUMBER=1 # This should be the actual sequence number of the message sent.

	# 2. Revoke a message.
	# TODO:
	# openim::test::revoke_msg "${RECV_USER_ID}" "si_${SEND_USER_ID}_${RECV_USER_ID}" "${SEQ_NUMBER}"

	# 4. Clear all messages for a user.
	openim::test::user_clear_all_msg "${RECV_USER_ID}"

	# Log the completion of the message test suite.
	openim::log::success "Message test suite completed successfully."
}

#################################### Man Module ####################################

# TODO:

openim::test::man() {
	openim::log::info "TODO: openim test man"
}

#################################### Build Module ####################################

# Function: openim::test::smoke
# Purpose: Performs a series of basic tests to validate the core functionality of the system.
# These are preliminary checks to ensure that the most crucial operations like user registration
# and account checking are operational.
openim::test::smoke() {
	openim::register_user
	openim::test::check_account
	openim::test::register_and_check
}

# Function: openim::test::api
# Purpose: This function is a collection of API test calls that cover various aspects of the
# service such as authentication, user operations, friend management, group interactions, and
# message handling. It is used to verify the integrity and functionality of API endpoints.
openim::test::api() {
	openim::test::auth
	openim::test::user
	openim::test::friend
	openim::test::group
	openim::test::msg
}

# Function: openim::test::test
# Purpose: This is the comprehensive test function that invokes all individual test functions.
# It ensures that each component of the service is tested, utilizing utility functions for
# environment checking and completing with a success message if all tests pass.
openim::test::test() {
	openim::util::require-jq
	openim::test::smoke
	openim::test::man
	openim::test::api

	openim::log::info "$(echo -e '\033[32mcongratulations, all test passed!\033[0m')"
}

# Main execution logic: This conditional block checks if the script's arguments match any known
# test function patterns and, if so, evaluates the function call. This allows for specific test
# functions to be triggered based on the passed arguments.
if [[ "$*" =~ openim::test:: ]]; then
	eval $*
fi