/**
 * @file    Chat.cs
 * 
 *  @date		2025 ~ Presents
 *  @copyright	Copyright © Com2uS Platform Corporation. All Right Reserved.
 *  @author		disker
 *  @since		25.0.0
 */
using UnityEngine;
using System;
using System.Text;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.Runtime.InteropServices;
using System.IO;

/**
 *  @defgroup Chat
 *  @{
 *  \~korean
 * @brief Hive 채팅 서비스는 실시간 채팅, 그룹 채팅, 1:1 채팅, 사용자 간 차단 기능 등 앱에서 원활한 채팅을 할 수 있도록 핵심 기능을 제공한다.<br/>
 *
 *  \~english
 * @brief The Hive Chat service provides essential features for seamless chat within the app, including real-time chat, group chat, one-on-one chat, and user blocking functionality.<br/>
 *
 *  \~
 *
 */
namespace hive
{
    /**
     *  \~korean
     * @brief Hive 채팅 서비스는 실시간 채팅, 그룹 채팅, 1:1 채팅, 사용자 간 차단 기능 등 앱에서 원활한 채팅을 할 수 있도록 핵심 기능을 제공한다.<br/>
     * 또 AI 채팅 필터링 기능으로 금칙어와 광고성 텍스트를 감지, 차단해 사용자 환경을 개선할 수 있다.<br/>
     *
     *  \~english
     * @brief The Hive Chat service provides essential features for seamless chat within the app, including real-time chat, group chat, one-on-one chat, and user blocking functionality.<br/>
     * Additionally, the AI chat filtering feature helps detect and block prohibited words and promotional text, enhancing the user experience.<br/><br/>
     *
     *  \~
     * @since 25.0.0
     * @ingroup Chat
     */
	public class Chat {

        /**
        *  \~korean
        * @brief Hive 채팅 서버 연결 연결 후 결과<br/>
        * @param API 호출 결과
        *   - ResultAPI.Code.Success 성공
        *   - ResultAPI.Code.ChatNeedSignIn Hive 인증이 진행되지 않음(인증 확인 필요)
        *   - ResultAPI.Code.ChatResponseError 이미 연결되거나 네트워크 에러 또는 기타 에러
        *
        *  \~english
        * @brief the result after connecting to the Hive chat server
        *   - ResultAPI.Code.Success Success
        *   - ResultAPI.Code.ChatNeedSignIn Hive is not signed in (sign-in check required)
        *   - ResultAPI.Code.ChatResponseError Already connected or Network error or other error
        *
        *  \~
        * @ingroup Chat
        */
		public delegate void onConnect(ResultAPI result);

        /**
        *  \~korean
        * @brief Hive 채팅 서버 재연결 후 결과<br/>
        * @param API 호출 결과
        *   - ResultAPI.Code.Success 성공
        *   - ResultAPI.Code.ChatNeedSignIn Hive 인증이 진행되지 않음(인증 확인 필요)
        *   - ResultAPI.Code.ChatResponseError 이미 연결되거나 네트워크 에러 또는 기타 에러
        * @param channelIds 성공적으로 재연결된 채널 ID 목록
        * @param failChannelIds 재연결 실패한 채널 ID 목록
        *
        *  \~english
        * @brief the result after reconnecting to the Hive chat server
        *   - ResultAPI.Code.Success Success
        *   - ResultAPI.Code.ChatNeedSignIn Hive is not signed in (sign-in check required)
        *   - ResultAPI.Code.ChatResponseError Already connected or Network error or other error
        * @param channelIds successfully reconnected channel ID list
        * @param failChannelIds failed to reconnect channel ID list
        *
        *  \~
        * @ingroup Chat
        */
        public delegate void onReconnect(ResultAPI result, List<String> channelIds, List<String> failChannelIds);

        /**
        *  \~korean
        * @brief Hive 채팅 서버 연결 해제 후 결과<br/>
        * @param API 호출 결과
        *   - ResultAPI.Code.Success 성공
        *   - ResultAPI.Code.ChatNotConnected Hive 채팅 서버와 연결되지 않음
        *   - ResultAPI.Code.ChatResponseError 네트워크 에러 또는 기타 에러
        *
        *  \~english
        * @brief the result after disconnecting from the Hive chat server
        * @param result API call result
        *   - ResultAPI.Code.Success Success
        *   - ResultAPI.Code.ChatNotConnected Hive Chat is not connected
        *   - ResultAPI.Code.ChatResponseError Network error or other error
        *
        *  \~
        * @ingroup Chat
        */
        public delegate void onDisconnect(ResultAPI result);

        /**
        *  \~korean
        * @brief 채널 메시지 전송 후 결과 값을 전달하는 리스너<br/>
        * @param API 호출 결과
        *   - ResultAPI.Code.Success 성공
        *   - ResultAPI.Code.ChatResponseError 네트워크 에러 또는 기타 에러
        *   - ResultAPI.Code.CommonUnknown 알 수 없는 에러
        *
        *  \~english
        * @brief Listener for delivering the result after sending a channel message<br/>
        * @param result API call result
        *   - ResultAPI.Code.Success Success
        *   - ResultAPI.Code.ChatResponseError Network error or other error
        *   - ResultAPI.Code.CommonUnknown Unknown error
        *
        *  \~
        * @ingroup Chat
        */
        public delegate void onChannelSendMessage(ResultAPI result, ChannelSendMessageParams retryParams);

        /**
        *  \~korean
        * @brief 1:1 메시지 전송 후 결과 값을 전달하는 리스너<br/>
        * @param API 호출 결과
        *   - ResultAPI.Code.Success 성공
        *   - ResultAPI.Code.ChatResponseError 네트워크 에러 또는 기타 에러
        *   - ResultAPI.Code.CommonUnknown 알 수 없는 에러
        *
        *  \~english
        * @brief Listener for delivering the result after sending a 1:1 message<br/>
        * @param result API call result
        *   - ResultAPI.Code.Success Success
        *   - ResultAPI.Code.ChatResponseError Network error or other error
        *   - ResultAPI.Code.CommonUnknown Unknown error
        *
        *  \~
        * @ingroup Chat
        */
        public delegate void onDirectSendMessage(ResultAPI result, DirectSendMessageParams retryParams);

        /**
        *  \~korean
        * @brief 채널 생성 후 결과<br/>
        * @param API 호출 결과
        *   - ResultAPI.Code.Success 성공
        *   - ResultAPI.Code.ChatNotConnected Hive 채팅 서버와 연결되지 않음 (재연결 필요)
        *   - ResultAPI.Code.ChatNeedSignIn Hive 인증이 진행되지 않음 (인증 확인 필요)
        *   - ResultAPI.Code.ChatResponseError 네트워크 에러 또는 기타 에러
        *
        *  \~english
        * @brief the result after channel creation
        * @param result API call result
        *   - ResultAPI.Code.Success Success
        *   - ResultAPI.Code.ChatNotConnected Hive Chat is not connected (reconnection required)
        *   - ResultAPI.Code.ChatNeedSignIn Hive is not signed in (sign-in check required)
        *   - ResultAPI.Code.ChatResponseError Network error or other error
        *
        *  \~
        * @ingroup Chat
        */
        public delegate void onCreateChannel(ResultAPI result);

        /**
        *  \~korean
        * @brief 채널 목록 조회 후 결과<br/>
        * @param API 호출 결과
        *   - ResultAPI.Code.Success 성공
        *   - ResultAPI.Code.ChatNotConnected Hive 채팅 서버와 연결되지 않음 (재연결 필요)
        *   - ResultAPI.Code.ChatNeedSignIn Hive 인증이 진행되지 않음 (인증 확인 필요)
        *   - ResultAPI.Code.ChatResponseError 네트워크 에러 또는 기타 에러
        * @param channels 조회된 채널 목록
        * @param channelPage 채널 페이지 정보
        *
        *  \~english
        * @brief The result after retrieving the list of channels
        * @param result API call result
        *   - ResultAPI.Code.Success Success
        *   - ResultAPI.Code.ChatNotConnected Hive Chat is not connected (reconnection required)
        *   - ResultAPI.Code.ChatNeedSignIn Hive is not signed in (sign-in check required)
        *   - ResultAPI.Code.ChatResponseError Network error or other error
        * @param channels List of channels retrieved
        * @param channelPage Channel page information
        *
        *  \~
        * @ingroup Chat
        */
        public delegate void onGetChannels(ResultAPI result, List<Channel> channels, ChannelPage channelPage);

        /**
        *  \~korean
        * @brief 채널 정보 조회 후 결과<br/>
        * @param API 호출 결과
        *   - ResultAPI.Code.Success 성공
        *   - ResultAPI.Code.ChatNotConnected Hive 채팅 서버와 연결되지 않음 (재연결 필요)
        *   - ResultAPI.Code.ChatNeedSignIn Hive 인증이 진행되지 않음 (인증 확인 필요)
        *   - ResultAPI.Code.ChatResponseError 네트워크 에러 또는 기타 에러
        * @param channel 채널 정보 (null일 수 있음)
        * @param members 채널에 속한 멤버 목록
        *
        *  \~english
        * @brief The result after retrieving channel information
        * @param result API call result
        *   - ResultAPI.Code.Success Success
        *   - ResultAPI.Code.ChatNotConnected Hive Chat is not connected (reconnection required)
        *   - ResultAPI.Code.ChatNeedSignIn Hive is not signed in (sign-in check required)
        *   - ResultAPI.Code.ChatResponseError Network error or other error
        * @param channel Channel information (may be null)
        * @param members List of members in the channel
        *
        *  \~
        * @ingroup Chat
        */
        public delegate void onGetChannelInfo(ResultAPI result, Channel channel, List<Member> members);

        /**
        *  \~korean
        * @brief 채널 멤버 목록 조회 후 결과<br/>
        * @param API 호출 결과
        *   - ResultAPI.Code.Success 성공
        *   - ResultAPI.Code.ChatNotConnected Hive 채팅 서버와 연결되지 않음 (재연결 필요)
        *   - ResultAPI.Code.ChatNeedSignIn Hive 인증이 진행되지 않음 (인증 확인 필요)
        *   - ResultAPI.Code.ChatResponseError 네트워크 에러 또는 기타 에러
        * @param members 채널에 속한 멤버 목록
        *
        *  \~english
        * @brief The result after retrieving the list of channel members
        * @param result API call result
        *   - ResultAPI.Code.Success Success
        *   - ResultAPI.Code.ChatNotConnected Hive Chat is not connected (reconnection required)
        *   - ResultAPI.Code.ChatNeedSignIn Hive is not signed in (sign-in check required)
        *   - ResultAPI.Code.ChatResponseError Network error or other error
        * @param members List of members in the channel
        *
        *  \~
        * @ingroup Chat
        */
        public delegate void onGetChannelMembers(ResultAPI result, List<Member> members);

        /**
        *  \~korean
        * @brief 채널 삭제 후 결과<br/>
        * @param API 호출 결과
        *   - ResultAPI.Code.Success 성공
        *   - ResultAPI.Code.ChatNotConnected Hive 채팅 서버와 연결되지 않음 (재연결 필요)
        *   - ResultAPI.Code.ChatNeedSignIn Hive 인증이 진행되지 않음 (인증 확인 필요)
        *   - ResultAPI.Code.ChatResponseError 네트워크 에러 또는 기타 에러
        *
        *  \~english
        * @brief The result after deleting the channel
        * @param result API call result
        *   - ResultAPI.Code.Success Success
        *   - ResultAPI.Code.ChatNotConnected Hive Chat is not connected (reconnection required)
        *   - ResultAPI.Code.ChatNeedSignIn Hive is not signed in (sign-in check required)
        *   - ResultAPI.Code.ChatResponseError Network error or other error
        *
        *  \~
        * @ingroup Chat
        */
        public delegate void onDeleteChannel(ResultAPI result);

        /**
        *  \~korean
        * @brief 채널 입장 후 결과<br/>
        * @param API 호출 결과
        *   - ResultAPI.Code.Success 성공
        *   - ResultAPI.Code.ChatNotConnected Hive 채팅 서버와 연결되지 않음 (재연결 필요)
        *   - ResultAPI.Code.ChatNeedSignIn Hive 인증이 진행되지 않음 (인증 확인 필요)
        *   - ResultAPI.Code.ChatResponseError 네트워크 에러 또는 기타 에러
        *
        *  \~english
        * @brief The result after entering the channel
        * @param result API call result
        *   - ResultAPI.Code.Success Success
        *   - ResultAPI.Code.ChatNotConnected Hive Chat is not connected (reconnection required)
        *   - ResultAPI.Code.ChatNeedSignIn Hive is not signed in (sign-in check required)
        *   - ResultAPI.Code.ChatResponseError Network error or other error
        *
        *  \~
        * @ingroup Chat
        */
        public delegate void onEnterChannel(ResultAPI result);

        /**
        *  \~korean
        * @brief 채널 퇴장 후 결과<br/>
        * @param API 호출 결과
        *   - ResultAPI.Code.Success 성공
        *   - ResultAPI.Code.ChatNotConnected Hive 채팅 서버와 연결되지 않음 (재연결 필요)
        *   - ResultAPI.Code.ChatNeedSignIn Hive 인증이 진행되지 않음 (인증 확인 필요)
        *   - ResultAPI.Code.ChatResponseError 네트워크 에러 또는 기타 에러
        *
        *  \~english
        * @brief The result after exiting the channel
        * @param result API call result
        *   - ResultAPI.Code.Success Success
        *   - ResultAPI.Code.ChatNotConnected Hive Chat is not connected (reconnection required)
        *   - ResultAPI.Code.ChatNeedSignIn Hive is not signed in (sign-in check required)
        *   - ResultAPI.Code.ChatResponseError Network error or other error
        *
        *  \~
        * @ingroup Chat
        */
        public delegate void onEixtChannel(ResultAPI result);

        /**
        *  \~korean
        * @brief 사용자 별 채널 목록 조회 후 결과<br/>
        * @param API 호출 결과
        *   - ResultAPI.Code.Success 성공
        *   - ResultAPI.Code.ChatNotConnected Hive 채팅 서버와 연결되지 않음 (재연결 필요)
        *   - ResultAPI.Code.ChatNeedSignIn Hive 인증이 진행되지 않음 (인증 확인 필요)
        *   - ResultAPI.Code.ChatResponseError 네트워크 에러 또는 기타 에러
        * @param channels 사용자와 연결된 채널 목록
        *
        *  \~english
        * @brief The result after retrieving the list of channels by user
        * @param result API call result
        *   - ResultAPI.Code.Success Success
        *   - ResultAPI.Code.ChatNotConnected Hive Chat is not connected (reconnection required)
        *   - ResultAPI.Code.ChatNeedSignIn Hive is not signed in (sign-in check required)
        *   - ResultAPI.Code.ChatResponseError Network error or other error
        * @param channels List of channels associated with the user
        *
        *  \~
        * @ingroup Chat
        */
        public delegate void onGetChannelsByUser(ResultAPI result, List<Channel> channels);

        /**
        *  \~korean
        * @brief 차단된 멤버 목록 조회 후 결과<br/>
        * @param API 호출 결과
        *   - ResultAPI.Code.Success 성공
        *   - ResultAPI.Code.ChatNotConnected Hive 채팅 서버와 연결되지 않음 (재연결 필요)
        *   - ResultAPI.Code.ChatNeedSignIn Hive 인증이 진행되지 않음 (인증 확인 필요)
        *   - ResultAPI.Code.ChatResponseError 네트워크 에러 또는 기타 에러
        * @param blockMembers 차단된 멤버 목록
        *
        *  \~english
        * @brief The result after retrieving the list of blocked members
        * @param result API call result
        *   - ResultAPI.Code.Success Success
        *   - ResultAPI.Code.ChatNotConnected Hive Chat is not connected (reconnection required)
        *   - ResultAPI.Code.ChatNeedSignIn Hive is not signed in (sign-in check required)
        *   - ResultAPI.Code.ChatResponseError Network error or other error
        * @param blockMembers List of blocked members
        *
        *  \~
        * @ingroup Chat
        */
        public delegate void onGetBlockMembers(ResultAPI result, List<BlockMember> blockMembers);

        /**
        *  \~korean
        * @brief 멤버 차단 후 결과<br/>
        * @param API 호출 결과
        *   - ResultAPI.Code.Success 성공
        *   - ResultAPI.Code.ChatNotConnected Hive 채팅 서버와 연결되지 않음 (재연결 필요)
        *   - ResultAPI.Code.ChatNeedSignIn Hive 인증이 진행되지 않음 (인증 확인 필요)
        *   - ResultAPI.Code.ChatResponseError 네트워크 에러 또는 기타 에러
        *
        *  \~english
        * @brief The result after blocking a member
        * @param result API call result
        *   - ResultAPI.Code.Success Success
        *   - ResultAPI.Code.ChatNotConnected Hive Chat is not connected (reconnection required)
        *   - ResultAPI.Code.ChatNeedSignIn Hive is not signed in (sign-in check required)
        *   - ResultAPI.Code.ChatResponseError Network error or other error
        *
        *  \~
        * @ingroup Chat
        */
        public delegate void onBlockMember(ResultAPI result);

        /**
        *  \~korean
        * @brief 멤버 차단 해제 후 결과<br/>
        * @param API 호출 결과
        *   - ResultAPI.Code.Success 성공
        *   - ResultAPI.Code.ChatNotConnected Hive 채팅 서버와 연결되지 않음 (재연결 필요)
        *   - ResultAPI.Code.ChatNeedSignIn Hive 인증이 진행되지 않음 (인증 확인 필요)
        *   - ResultAPI.Code.ChatResponseError 네트워크 에러 또는 기타 에러
        *
        *  \~english
        * @brief The result after unblocking a member
        * @param result API call result
        *   - ResultAPI.Code.Success Success
        *   - ResultAPI.Code.ChatNotConnected Hive Chat is not connected (reconnection required)
        *   - ResultAPI.Code.ChatNeedSignIn Hive is not signed in (sign-in check required)
        *   - ResultAPI.Code.ChatResponseError Network error or other error
        *
        *  \~
        * @ingroup Chat
        */
        public delegate void onUnblockMember(ResultAPI result);

        public delegate void onChannelMessageListQuery(ResultAPI result, ChannelMessageListQueryResponse response);
        public delegate void onChannelTranslationSetting(ResultAPI result);

        public delegate void onTranslate(ResultAPI result, TranslationData data);

        /**
        *  \~korean
        * @brief 리액션 추가/제거 후 결과<br/>
        *
        *  \~english
        * @brief Result after adding/removing a reaction<br/>
        *
        *  \~
        * @ingroup Chat
        */
        public delegate void onReaction(ResultAPI result, ReactionType reactionType);

        public static ConcurrentDictionary<String, ConnectionHandler> connectionHandlers = new ConcurrentDictionary<String, ConnectionHandler>();
        public static ConcurrentDictionary<String, ChannelHandler> channelHandlers = new ConcurrentDictionary<String, ChannelHandler>();
        public static ConcurrentDictionary<String, DirectMessageHandler> directMessageHandlers = new ConcurrentDictionary<String, DirectMessageHandler>();
        public static ConcurrentDictionary<String, UserHandler> userHandlers = new ConcurrentDictionary<String, UserHandler>();
        public static ConcurrentDictionary<String, CustomDataHandler> customDataHandlers = new ConcurrentDictionary<String, CustomDataHandler>();

        public static ConcurrentDictionary<String, ChannelSendMessageHandler> channelSendMessageHandlers = new ConcurrentDictionary<String, ChannelSendMessageHandler>();
        public static ConcurrentDictionary<String, DirectSendMessageHandler> directSendMessageHandlers = new ConcurrentDictionary<String, DirectSendMessageHandler>();
    

        /**
        *  \~korean
        * @brief [Deprecated] Hive 채팅 서버 연결<br/>
        * 이 API는 더 이상 사용을 권장하지 않으며, 향후 버전에서 제거될 예정입니다.<br/>
        * 대신 {connect(onConnect)}를 사용하세요.<br/>
        * <br/>
        * Hive 채팅 기능을 호출하기 전에 가장 먼저 호출되어야 하는 API로, 인증된 사용자 정보를 바탕으로 Hive 채팅 서버에 연결을 시도한다.<br/>
        * <br/>
        * 기본적으로 60초 이내에 연결되지 않으면 ResultAPI.Code.ChatResponseError 가 발생한다.<br/>
        * Configuration.setChatConnectionTimeout() API를 사용하여 Hive 채팅 서버 연결을 위한 최대 시간을 재 설정할 수 있다.<br/>
        * <br/>
        * 연결 상태를 감지하고 상태 변경 이벤트를 수신하기 위해 Chat.addConnectionHandler 이벤트 핸들러를 등록해야 한다.<br>
        *
        * @param extraData 사용자 설정 데이터 (예: 닉네임)
        * @param listener onConnect
        * @deprecated v25.2.0부터 사용 중단, 대신 {connect(onConnect)}를 사용
        *
        *  \~english
        * @brief [Deprecated] The result after attempting to connect to the Hive chat server<br/>
        * This is the first API that must be called before accessing the Hive chat feature. It attempts to connect to the Hive chat server based on the authenticated user information.<br/>
        * Please use {connect(onConnect)} instead.<br/>
        * <br/>
        * By default, if the connection is not established within 60 seconds, ResultAPI.Code.ChatResponseError will occur.<br/>
        * The maximum time for connecting to the Hive chat server can be reconfigured using the Configuration.setChatConnectionTimeout() API.<br/>
        * <br/>
        * To detect the connection status and receive status change events, you need to register the event handler with Chat.addConnectionHandler.<br>
        *
        * @param extraData User settings data (e.g., nickname)
        * @param listener onConnect
        * @deprecated Deprecated since v25.2.0, use {connect(onConnect)} instead
        *
        *  \~
        * @ingroup Chat
        */
        public static void connect(String extraData, onConnect listener) {
            connect(listener);
		}

        /**
        *  \~korean
        * @brief Hive 채팅 서버 연결<br/>
        * Hive 채팅 기능을 호출하기 전에 가장 먼저 호출되어야 하는 API로, 인증된 사용자 정보를 바탕으로 Hive 채팅 서버에 연결을 시도한다.<br/>
        * <br/>
        * 기본적으로 60초 이내에 연결되지 않으면 ResultAPI.Code.ChatResponseError 가 발생한다.<br/>
        * Configuration.setChatConnectionTimeout() API를 사용하여 Hive 채팅 서버 연결을 위한 최대 시간을 재 설정할 수 있다.<br/>
        * <br/>
        * 연결 상태를 감지하고 상태 변경 이벤트를 수신하기 위해 Chat.addConnectionHandler 이벤트 핸들러를 등록해야 한다.<br>
        *
        * @param listener onConnect
        *
        *  \~english
        * @brief The result after attempting to connect to the Hive chat server<br/>
        * This is the first API that must be called before accessing the Hive chat feature. It attempts to connect to the Hive chat server based on the authenticated user information.<br/>
        * <br/>
        * By default, if the connection is not established within 60 seconds, ResultAPI.Code.ChatResponseError will occur.<br/>
        * The maximum time for connecting to the Hive chat server can be reconfigured using the Configuration.setChatConnectionTimeout() API.<br/>
        * <br/>
        * To detect the connection status and receive status change events, you need to register the event handler with Chat.addConnectionHandler.<br>
        *
        * @param listener onConnect
        *
        *  \~
        * @ingroup Chat
        */
        public static void connect(onConnect listener) {
            JSONObject jsonParam = HIVEUnityPlugin.createParam("Chat", "connect", listener);

            HIVEUnityPlugin.callNative (jsonParam);
        }

        /**
        *  \~korean
        * @brief Hive 채팅 서버 재연결<br/>
        * Hive 채팅 서버와 재연결한다.<<br/>
        * <br/>
        * 재연결은 기존의 접속이 끊긴지 10분이 지나지 않았다면, 기존에 접속되어있던 채널에 다시 접속한다.<br/>
        * 마지막으로 연결이 끊긴지 10분이 지났거나, 이전 연결기록이 없다면 connect와 동일하게 동작한다.<br/>
        * <br/>
        * 연결 상태를 감지하고 상태 변경 이벤트를 수신하기 위해 Chat.addConnectionHandler 이벤트 핸들러를 등록해야 한다.<br>
        * 
        * @param listener onReconnect
        *
        *  \~english
        * @brief Reconnect to Hive chat server<br/>
        * Reconnects to the Hive chat server.<br/>
        * <br/>
        * The reconnection will rejoin the previously connected channels if the disconnection occurred less than 10 minutes ago.<br/>
        * If the last disconnection was more than 10 minutes ago or there is no previous connection record, this will behave the same as connect.<br/>
        * <br/>
        * To detect connection status and receive status change events, you must register the Chat.addConnectionHandler event handler.<br>
        * 
        * @param listener onReconnect callback
        *
        *  \~
        * @ingroup Chat
        */
        public static void reconnect(onReconnect listener) {
            JSONObject jsonParam = HIVEUnityPlugin.createParam("Chat", "reconnect", listener);

            HIVEUnityPlugin.callNative (jsonParam);
        }

        /**
        *  \~korean
        * @brief Hive 채팅 서버 연결 해제<br/>
        * Hive 채팅 서버와 연결을 해제한다. 인증된 사용자 정보가 사인 아웃 될 때, 이 API는 자동호출 된다.<br/>
        *
        * @param listener onDisconnect
        * 
        *  \~english
        * @brief Disconnects from the Hive chat server<br/>
        * This API is automatically called when the authenticated user information is signed out.<br/>
        * 
        * @param listener onDisconnect
        *
        *  \~
        * @ingroup Chat
        */
        public static void disconnect(onDisconnect listener) {

            JSONObject jsonParam = HIVEUnityPlugin.createParam("Chat", "disconnect", listener);

            HIVEUnityPlugin.callNative (jsonParam);
        }

        /**
        *  \~korean
        * @brief 현재 사용자의 Hive 채팅 서버 연결 상태를 조회<br/>
        * Hive 채팅 서버와의 연결 상태를 확인한다.<br/>
        *
        * @return 연결되었으면 true, 아니면 false 반환
        * 
        *  \~english
        * @brief Retrieves the current user's Hive chat server connection status<br/>
        * Checks the connection status to the Hive chat server.<br/>
        *
        * @return returns true if connected, false otherwise.
        *
        *   \~
        * @ingroup Chat
        */
        public static Boolean isConnected() {

            JSONObject jsonParam = HIVEUnityPlugin.createParam("Chat", "isConnected", null);

			JSONObject resJsonObject = HIVEUnityPlugin.callNative (jsonParam);

			Boolean isConnected = false;
			resJsonObject.GetField (ref isConnected, "isConnected");
			
			return isConnected;
        }

        /**
        *  \~korean
        * @brief 채널 메시지 전송<br/>
        * 사용자가 입장한 채널에 메시지를 전송하며, ChannelSendMessageParams 객체를 생성하여 메시지 전송 정보를 설정할 수 있다.<br/>
        * <br/>
        * 전달된 채널 메시지를 수신하기 위해 Chat.addChannelHandler 이벤트 핸들러를 등록해야 한다.<br/>
        *
        * @param param ChannelSendMessageParams 메시지 전송 정보
        * 
        *  \~english
        * @brief Send channel message<br/>
        * Sends a message to the channel the user has joined, and allows configuring message transmission details
        * by creating a ChannelSendMessageParams object.<br/>
        * <br/>
        * To receive the sent channel message, you need to register an event handler using Chat.addChannelHandler.<br/>
        *
        * @param param ChannelSendMessageParams message sending details
        *
        *  \~
        * @ingroup Chat
        */
        public static void sendMessage(ChannelSendMessageParams param) {

            JSONObject jsonParam = HIVEUnityPlugin.createParam("Chat", "sendMessageWithChannelSendMessageParams", null);
            if (param != null) jsonParam.AddField ("params", param.TOJSON().ToString());

            HIVEUnityPlugin.callNative (jsonParam);
        }

        /**
        *  \~korean
        * @brief 채널 메시지 전송<br/>
        * 사용자가 입장한 채널에 메시지를 전송하며, ChannelSendMessageParams 객체를 생성하여 메시지 전송 정보를 설정할 수 있다.<br/>
        * <br/>
        * 메시지 전송 결과는 전달된 onChannelSendMessage 콜백을 통해 받을 수 있으며,<br/>
        * 전역적으로 메시지를 수신하려면 Chat.addChannelHandler 이벤트 핸들러를 등록해야 한다.<br/>
        *
        * @param param ChannelSendMessageParams 메시지 전송 정보
        *
        * \~english
        * @brief Send channel message<br/>
        * Sends a message to the channel the user has joined, with details configured using a ChannelSendMessageParams object.<br/>
        * <br/>
        * The result of the message sending will be received through the provided onChannelSendMessage callback.<br/>
        * To receive channel messages globally, you should register an event handler using Chat.addChannelHandler.<br/>
        *
        * @param param ChannelSendMessageParams message sending details
        *
        * \~
        * @ingroup Chat
        */
        public static void sendMessage(ChannelSendMessageParams param, onChannelSendMessage listener) {

            JSONObject jsonParam = HIVEUnityPlugin.createParam("Chat", "sendMessageWithChannelSendMessageParams", null);
            if (param != null) jsonParam.AddField ("params", param.TOJSON().ToString());
            if (listener != null) {
                String uniqueKey = genUniqueKey();
                channelSendMessageHandlers.TryAdd(uniqueKey, new ChannelSendMessageHandler(listener, param));

                jsonParam.AddField ("uniqueKey", uniqueKey);
            }

            HIVEUnityPlugin.callNative (jsonParam);
        }

        /**
        *  \~korean
        * @brief 1:1 메시지 전송<br/>
        * 특정 대상 사용자에게 메시지를 전송하며, DirectSendMessageParams 객체를 생성하여 메시지 전송 정보를 설정할 수 있다.<br/>
        * <br/>
        * 전달된 1:1 메시지를 수신하기 위해 Chat.addDirectMessageHandler 이벤트 핸들러를 등록해야 한다.<br/>
        *
        * @param param DirectSendMessageParams 메시지 전송 정보
        * 
        *  \~english
        * @brief Send 1:1 message<br/>
        * Sends a message to a specific target user, and allows configuring message transmission details
        * by creating a DirectSendMessageParams object.<br/>
        * <br/>
        * To receive the sent 1:1 message, you need to register an event handler using Chat.addDirectMessageHandler.<br/>
        *
        * @param param DirectSendMessageParams message sending details
        *
        *  \~
        * @ingroup Chat
        */
        public static void sendMessage(DirectSendMessageParams param) {
            
            JSONObject jsonParam = HIVEUnityPlugin.createParam("Chat", "sendMessageWithDirectSendMessageParams", null);
            if (param != null) jsonParam.AddField ("params", param.TOJSON().ToString());

            HIVEUnityPlugin.callNative (jsonParam);
        }

        /**
        *  \~korean
        * @brief 1:1 메시지 전송<br/>
        * 특정 대상 사용자에게 메시지를 전송하며, DirectSendMessageParams 객체를 생성하여 메시지 전송 정보를 설정할 수 있다.<br/>
        * <br/>
        * 메시지 전송 결과는 전달된 onDirectSendMessage 콜백을 통해 받을 수 있으며,<br/>
        * 전역적으로 메시지를 수신하려면 Chat.addDirectMessageHandler 이벤트 핸들러를 등록해야 한다.<br/>
        *
        * @param param DirectSendMessageParams 메시지 전송 정보
        *
        * \~english
        * @brief Send 1:1 message<br/>
        * Sends a message to a specific target user, with details configured using a DirectSendMessageParams object.<br/>
        * <br/>
        * The result of the message sending will be received through the provided onDirectSendMessage callback.<br/>
        * To receive channel messages globally, you should register an event handler using Chat.addDirectMessageHandler.<br/>
        *
        * @param param DirectSendMessageParams message sending details
        *
        * \~
        * @ingroup Chat
        */
        public static void sendMessage(DirectSendMessageParams param, onDirectSendMessage listener) {
            
            JSONObject jsonParam = HIVEUnityPlugin.createParam("Chat", "sendMessageWithDirectSendMessageParams", null);
            if (param != null) jsonParam.AddField ("params", param.TOJSON().ToString());
            if (listener != null) {
                String uniqueKey = genUniqueKey();
                directSendMessageHandlers.TryAdd(uniqueKey, new DirectSendMessageHandler(listener, param));

                jsonParam.AddField ("uniqueKey", uniqueKey);
            }

            HIVEUnityPlugin.callNative (jsonParam);
        }

        /**
        *  \~korean
        * @brief Hive 채팅 서버와 연결 상태를 감지하고 상태 변경 이벤트 수신<br/>
        * Hive 채팅 서버와 연결 상태를 감지하고 상태 변경 이벤트를 수신한다.<br/>
        *
        * @param uniqueKey 사용자 정의 고유 키
        * @param connectionHandler ConnectionHandler 연결 상태 핸들러
        * 
        *  \~english
        * @brief Detects the connection status with the Hive chat server and listens for status change events.<br/>
        * Detects the connection status with the Hive chat server and listens for status change events.<br/>
        *
        * @param uniqueKey custom unique key
        * @param connectionHandler ConnectionHandler connection status handler
        *
        *  \~
        * @ingroup Chat
        */
        public static void addConnectionHandler(String uniqueKey, ConnectionHandler connectionHandler) {
            try
            {
                Chat.connectionHandlers.AddOrUpdate(uniqueKey, connectionHandler, (existKey, existValue) => connectionHandler);
                JSONObject jsonParam = HIVEUnityPlugin.createParam("Chat", "addConnectionListener", null);
                jsonParam.AddField ("uniqueKey", uniqueKey);
                HIVEUnityPlugin.callNative (jsonParam);
            }
            catch (Exception ex)
            {
                Debug.Log("addConnectionHandler exception: " + ex.Message.ToString());
            }
        }

        /**
        *  \~korean
        * @brief Hive 채팅 서버에 연결된 사용자와 채널 간의 이벤트를 감지하고 변경 이벤트 수신<br/>
        * Hive 채팅 서버에 연결된 사용자와 채널 간의 이벤트를 감지하고 변경 이벤트를 수신한다.<br/>
        *
        * @param uniqueKey 사용자 정의 고유 키
        * @param channelHandler ChannelHandler 채널 이벤트 핸들러
        * 
        *  \~english
        * @brief Detects events between the connected user and the Hive chat server channel, and listens for change events.<br/>
        * Detects events between the connected user and the Hive chat server channel, and listens for change events.<br/>
        *
        * @param uniqueKey custom unique key
        * @param channelHandler ChannelHandler channel event handler
        *
        *  \~
        * @ingroup Chat
        */
        public static void addChannelHandler(String uniqueKey, ChannelHandler channelHandler) {
            try
            {
                Chat.channelHandlers.AddOrUpdate(uniqueKey, channelHandler, (existKey, existValue) => channelHandler);
                JSONObject jsonParam = HIVEUnityPlugin.createParam("Chat", "addChannelListener", null);
                jsonParam.AddField ("uniqueKey", uniqueKey);
                HIVEUnityPlugin.callNative (jsonParam);
            }
            catch (Exception ex)
            {
                Debug.Log("addChannelHandler exception " + ex.Message.ToString());
            }
            
        }

        /**
        * \~korean
        * @brief Hive 채팅 서버에 연결된 사용자에게 전달된 1:1 메시지 이벤트를 감지하고 이벤트 수신<br/>
        * Hive 채팅 서버에 연결된 사용자에게 전달된 1:1 메시지 이벤트를 감지하고 해당 이벤트를 수신한다.<br/>
        *
        * @param uniqueKey 사용자 정의 고유 키
        * @param directMessageHandler DirectMessageHandler 1:1 메시지 이벤트 핸들러
        * 
        * \~english
        * @brief Detects 1:1 message events delivered to the connected user on the Hive chat server and listens for these events.<br/>
        * Detects 1:1 message events delivered to the connected user on the Hive chat server and listens for these events.<br/>
        *
        * @param uniqueKey custom unique key
        * @param directMessageHandler DirectMessageHandler 1:1 message event handler
        *
        *  \~
        * @ingroup Chat
        */
        [System.Obsolete("Deprecated since v25.4.0. Use addUserHandler instead.")]
        public static void addDirectMessageHandler(String uniqueKey, DirectMessageHandler directMessageHandler) {
            try
            {
                Chat.directMessageHandlers.AddOrUpdate(uniqueKey, directMessageHandler, (existKey, existValue) => directMessageHandler);
                JSONObject jsonParam = HIVEUnityPlugin.createParam("Chat", "addDirectMessageListener", null);
                jsonParam.AddField ("uniqueKey", uniqueKey);
                HIVEUnityPlugin.callNative (jsonParam);
            }
            catch (Exception ex)
            {
                Debug.Log("addDirectMessageHandler exception " + ex.Message.ToString());
            }
        }

        /**
        * \~korean
        * @brief Hive 채팅 서버에 연결된 사용자와 관련된 이벤트를 감지하고 수신하는 리스너를 등록합니다.<br/>
        * 유저 고유 키를 기준으로 UserHandler를 등록하여, 해당 유저와 관련된 DirectMessage 및 NoticeMessage 이벤트를 감지하고 수신합니다.<br/>
        *
        * @param uniqueKey 사용자 정의 고유 키
        * @param userHandler UserHandler 사용자 이벤트 리스너
        * 
        * \~english
        * @brief Registers a listener that detects and receives user-related events on the connected Hive chat server.<br/>
        * Registers a UserHandler using a unique key to detect and receive events such as DirectMessage and NoticeMessage for the specified user.<br/>
        *
        * @param uniqueKey custom unique key
        * @param userHandler UserHandler for user-related events
        *
        * \~
        * @ingroup Chat
        */
        public static void addUserHandler(String uniqueKey, UserHandler userHandler) {
            try
            {
                Chat.userHandlers.AddOrUpdate(uniqueKey, userHandler, (existKey, existValue) => userHandler);
                JSONObject jsonParam = HIVEUnityPlugin.createParam("Chat", "addUserListener", null);
                jsonParam.AddField ("uniqueKey", uniqueKey);
                HIVEUnityPlugin.callNative (jsonParam);
            }
            catch (Exception ex)
            {
                Debug.Log("addUserHandler exception " + ex.Message.ToString());
            }
        }

        /**
        *  \~korean
        * @brief Hive 채팅 서버에 연결된 사용자에게 전달된 커스텀 데이터를 감지하고 수신하는 리스너를 등록합니다.<br/>
        * 유저 고유 키를 기준으로 CustomDataHandler를 등록하여, 해당 유저와 관련된 커스텀 데이터를 수신합니다.<br/>
        *
        * @param uniqueKey 사용자 정의 고유 키
        * @param customDataHandler CustomDataHandler 커스텀 데이터 이벤트 리스너
        * 
        *  \~english
        * @brief Registers a listener that detects and receives custom data for the connected user on the Hive chat server.<br/>
        * Registers a CustomDataHandler using a unique key to receive custom data related to the specified user.<br/>
        *
        * @param uniqueKey custom unique key
        * @param customDataHandler CustomDataHandler for custom data events
        *
        *  \~
        * @ingroup Chat
        */
        public static void addCustomDataHandler(String uniqueKey, CustomDataHandler customDataHandler) {
            try
            {
                Chat.customDataHandlers.AddOrUpdate(uniqueKey, customDataHandler, (existKey, existValue) => customDataHandler);
                JSONObject jsonParam = HIVEUnityPlugin.createParam("Chat", "addCustomDataListener", null);
                jsonParam.AddField ("uniqueKey", uniqueKey);
                HIVEUnityPlugin.callNative (jsonParam);
            }
            catch (Exception ex)
            {
                Debug.Log("addCustomDataHandler exception " + ex.Message.ToString());
            }
        }

        /**
        *  \~korean
        * @brief 등록된 연결 이벤트 핸들러(addConnectionHandler) 제거<br/>
        * 등록된 연결 이벤트 핸들러를 제거한다.<br/>
        *
        * @param uniqueKey 사용자 정의 고유 키
        * 
        *  \~english
        * @brief Removes the registered connection event handler (addConnectionHandler)<br/>
        * Removes the registered connection event handler.<br/>
        *
        * @param uniqueKey custom unique key
        *
        *  \~
        * @ingroup Chat
        */
        public static void removeConnectionHandler(String uniqueKey) {
            try
            {
                if (Chat.connectionHandlers.TryRemove(uniqueKey, out _))
                {
                    JSONObject jsonParam = HIVEUnityPlugin.createParam("Chat", "removeConnectionListener", null);
                    jsonParam.AddField ("uniqueKey", uniqueKey);
                    HIVEUnityPlugin.callNative (jsonParam);
                }
                else
                {
                    Debug.Log("removeConnectionHandler uniqueKey not exist. " + uniqueKey);
                }
            }
            catch (Exception ex)
            {
                Debug.Log("removeConnectionHandler exception " + ex.Message.ToString());
            }
        }

        /**
        *  \~korean
        * @brief 등록된 채널 이벤트 핸들러(addChannelHandler) 제거<br/>
        * 등록된 채널 이벤트 핸들러를 제거한다.<br/>
        *
        * @param uniqueKey 사용자 정의 고유 키
        * 
        *  \~english
        * @brief Removes the registered channel event handler (addChannelHandler)<br/>
        * Removes the registered channel event handler.<br/>
        *
        * @param uniqueKey custom unique key
        *
        *  \~
        * @ingroup Chat
        */
        public static void removeChannelHandler(String uniqueKey) {
            try
            {
                if (Chat.channelHandlers.TryRemove(uniqueKey, out _))
                {
                    JSONObject jsonParam = HIVEUnityPlugin.createParam("Chat", "removeChannelListener", null);
                    jsonParam.AddField ("uniqueKey", uniqueKey);
                    HIVEUnityPlugin.callNative (jsonParam);
                }
                else
                {
                    Debug.Log("removeChannelHandler uniqueKey not exist. " + uniqueKey);
                }
            }
            catch (Exception ex)
            {
                Debug.Log("removeChannelHandler exception " + ex.Message.ToString());
            }

        }

        /**
        *  \~korean
        * @brief 등록된 1:1 메시지 이벤트 핸들러(addDirectMessageHandler) 제거<br/>
        * 등록된 1:1 메시지 이벤트 핸들러를 제거한다.<br/>
        *
        * @param uniqueKey 사용자 정의 고유 키
        * 
        *  \~english
        * @brief Removes the registered 1:1 message event handler (addDirectMessageHandler)<br/>
        * Removes the registered 1:1 message event handler.<br/>
        *
        * @param uniqueKey custom unique key
        *
        *  \~
        * @ingroup Chat
        */
        public static void removeDirectMessageHandler(String uniqueKey) {
            try
            {
                if (Chat.directMessageHandlers.TryRemove(uniqueKey, out _))
                {
                    JSONObject jsonParam = HIVEUnityPlugin.createParam("Chat", "removeDirectMessageListener", null);
                    jsonParam.AddField ("uniqueKey", uniqueKey);
                    HIVEUnityPlugin.callNative (jsonParam);
                }
                else
                {
                    Debug.Log("removeDirectMessageHandler uniqueKey not exist. " + uniqueKey);
                }
            }
            catch (Exception ex)
            {
                Debug.Log("removeDirectMessageHandler exception " + ex.Message.ToString());
            }
        }

        /**
        *  \~korean
        * @brief 등록된 사용자 이벤트 리스너(addUserHandler) 제거<br/>
        * 등록된 UserHandler를 uniqueKey 기준으로 제거하며, 해당 유저와 관련된 DirectMessage 및 NoticeMessage 이벤트 수신을 중단합니다.<br/>
        *
        * @param uniqueKey 사용자 정의 고유 키
        * 
        *  \~english
        * @brief Removes the registered user event listener (addUserHandler)<br/>
        * Removes the registered UserHandler by uniqueKey, and stops receiving user-related events such as DirectMessage and NoticeMessage.<br/>
        *
        * @param uniqueKey custom unique key
        *
        *  \~
        * @ingroup Chat
        */
        public static void removeUserHandler(String uniqueKey) {
            try
            {
                if (Chat.userHandlers.TryRemove(uniqueKey, out _))
                {
                    JSONObject jsonParam = HIVEUnityPlugin.createParam("Chat", "removeUserListener", null);
                    jsonParam.AddField("uniqueKey", uniqueKey);
                    HIVEUnityPlugin.callNative(jsonParam);
                }
                else
                {
                    Debug.Log("removeUserHandler uniqueKey not exist. " + uniqueKey);
                }
            }
            catch (Exception ex)
            {
                Debug.Log("removeUserHandler exception " + ex.Message.ToString());
            }
        }

        /**
        *  \~korean
        * @brief 등록된 커스텀 데이터 이벤트 리스너(addCustomDataHandler) 제거<br/>
        * 등록된 CustomDataHandler를 uniqueKey 기준으로 제거하며, 해당 유저와 관련된 커스텀 데이터 수신을 중단합니다.<br/>
        *
        * @param uniqueKey 사용자 정의 고유 키
        * 
        *  \~english
        * @brief Removes the registered custom data event listener (addCustomDataHandler)<br/>
        * Removes the registered CustomDataHandler by uniqueKey, and stops receiving custom data related to the specified user.<br/>
        *
        * @param uniqueKey custom unique key
        *
        *  \~
        * @ingroup Chat
        */
        public static void removeCustomDataHandler(String uniqueKey) {
            try
            {
                if (Chat.customDataHandlers.TryRemove(uniqueKey, out _))
                {
                    JSONObject jsonParam = HIVEUnityPlugin.createParam("Chat", "removeCustomDataHandler", null);
                    jsonParam.AddField("uniqueKey", uniqueKey);
                    HIVEUnityPlugin.callNative(jsonParam);
                }
                else
                {
                    Debug.Log("removeCustomDataHandler uniqueKey not exist. " + uniqueKey);
                }
            }
            catch (Exception ex)
            {
                Debug.Log("removeCustomDataHandler exception " + ex.Message.ToString());
            }
        }

        /**
        *  \~korean
        * @brief 채널 생성<br/>
        * 새로운 대화 채널을 생성한다.<br/>
        *
        * @param param 채널 생성에 필요한 매개변수를 포함한 객체
        * @param listener onCreateChannel
        * 
        *  \~english
        * @brief Create channel<br/>
        * Creates a new conversation channel.<br/>
        *
        * @param param object containing the parameters to create the channel
        * @param listener onCreateChannel
        *
        *  \~
        * @ingroup Chat
        */
        public static void createChannel(CreateChannelParams param, onCreateChannel listener) {

            JSONObject jsonParam = HIVEUnityPlugin.createParam("Chat", "createChannel", listener);
            if (param != null) jsonParam.AddField ("params", param.TOJSON().ToString());

            HIVEUnityPlugin.callNative (jsonParam);
        }

        /**
        * \~korean
        * @brief 현재 생성된 채널 목록 조회<br/>
        * 현재 생성된 채널 목록을 조회한다. GetChannelsParams 객체를 구성하여 조회하고자 하는 채널에 대한 필터를 설정할 수 있다.<br/>
        *
        * @param param 채널을 필터링하기 위한 객체
        * @param listener onGetChannels
        * 
        * \~english
        * @brief Retrieve list of currently created channels<br/>
        * Retrieves the list of currently created channels. You can configure a GetChannelsParams object to set filters for the channels you want to retrieve.<br/>
        *
        * @param param object to filter the channels
        * @param listener onGetChannels
        *
        *  \~
        * @ingroup Chat
        */
        public static void getChannels(GetChannelsParams param, onGetChannels listener) {

            JSONObject jsonParam = HIVEUnityPlugin.createParam("Chat", "getChannels", listener);
            if (param != null) jsonParam.AddField ("params", param.TOJSON().ToString());

            HIVEUnityPlugin.callNative (jsonParam);
        }

        /**
        *  \~korean
        * @brief 채널 정보 조회<br/>
        * 특정 단일 채널의 상세 정보를 조회한다.<br/>
        *
        * @param channelId 정보를 조회할 채널의 ID
        * @param listener onGetChannelInfo
        * 
        *  \~english
        * @brief Retrieve channel information<br/>
        * Retrieves the detailed information of a specific channel.<br/>
        *
        * @param channelId ID of the channel to retrieve information
        * @param listener onGetChannelInfo
        *
        *  \~
        * @ingroup Chat
        */
        public static void getChannelInfo(String channelId, onGetChannelInfo listener) {

            JSONObject jsonParam = HIVEUnityPlugin.createParam("Chat", "getChannelInfo", listener);
            jsonParam.AddField ("channelId", channelId);

            HIVEUnityPlugin.callNative (jsonParam);
        }

        /**
        *  \~korean
        * @brief 채널 참여자 정보 조회<br/>
        * 특정 채널의 참여자 정보를 조회한다.<br/>
        *
        * @param channelId 정보를 조회할 채널의 ID
        * @param listener onGetChannelMembers
        * 
        *  \~english
        * @brief Retrieve channel participant information<br/>
        * Retrieves the participant information of a specific channel.<br/>
        *
        * @param channelId ID of the channel to retrieve participant information
        * @param listener onGetChannelMembers
        *
        *  \~
        * @ingroup Chat
        */
        public static void getChannelMembers(String channelId, onGetChannelMembers listener) {
            JSONObject jsonParam = HIVEUnityPlugin.createParam("Chat", "getChannelMembers", listener);
            jsonParam.AddField ("channelId", channelId);

            HIVEUnityPlugin.callNative (jsonParam);
        }

        /**
        *  \~korean
        * @brief 채널 삭제<br/>
        * 채널을 삭제한다.<br/>
        *
        * @param channelId 삭제할 채널의 ID
        * @param listener onDeleteChannel
        * 
        *  \~english
        * @brief Delete channel<br/>
        * Deletes the channel.<br/>
        *
        * @param channelId ID of the channel to delete
        * @param listener onDeleteChannel
        *
        *  \~
        * @ingroup Chat
        */
        public static void deleteChannel(String channelId, onDeleteChannel listener) {
            JSONObject jsonParam = HIVEUnityPlugin.createParam("Chat", "deleteChannel", listener);
            jsonParam.AddField ("channelId", channelId);

            HIVEUnityPlugin.callNative (jsonParam);
        }

        /**
        *  \~korean
        * @brief 채널 입장<br/>
        * 채널에 입장한다.<br/>
        *
        * @param param 채널 입장 정보
        * @param listener onEnterChannel
        * 
        *  \~english
        * @brief Enter channel<br/>
        * Enters the channel.<br/>
        *
        * @param param The information of the channel to enter
        * @param listener onEnterChannel
        *
        *  \~
        * @ingroup Chat
        */
        public static void enterChannel(EnterChannelParams param, onEnterChannel listener) {
            JSONObject jsonParam = HIVEUnityPlugin.createParam("Chat", "enterChannel", listener);
            if (param != null) jsonParam.AddField ("params", param.TOJSON().ToString());

            HIVEUnityPlugin.callNative (jsonParam);
        }

        /**
        * \~korean
        * @brief 채널 퇴장<br/>
        * 현재 사용자가 참여한 채널에서 퇴장합니다. 채널 소유자가 퇴장하는 경우, 해당 채널은 삭제됩니다.<br/>
        *
        * @param channelId 퇴장할 채널 ID
        * @param listener onExitChannel
        * 
        * \~english
        * @brief Exit Channel<br/>
        * Exit the channel the current user is participating in. If the channel owner leaves, the channel will be deleted.<br/>
        *
        * @param channelId ID of the channel to exit
        * @param listener onExitChannel
        *
        *  \~
        * @ingroup Chat
        */
        public static void exitChannel(String channelId, onEixtChannel listener) {
            JSONObject jsonParam = HIVEUnityPlugin.createParam("Chat", "exitChannel", listener);
            jsonParam.AddField ("channelId", channelId);

            HIVEUnityPlugin.callNative (jsonParam);
        }

        /**
        *  \~korean
        * @brief 사용자 참여 채널 조회<br/>
        * 현재 사용자의 참여 중인 채널 목록을 조회한다.<br/>
        *
        * @param listener onGetChannelsByUser
        * 
        *  \~english
        * @brief Retrieve channels the user is participating in<br/>
        * Retrieves the list of channels the current user is participating in.<br/>
        *
        * @param listener onGetChannelsByUser
        *
        *  \~
        * @ingroup Chat
        */
        public static void getChannelsByUser(onGetChannelsByUser listener) {
            JSONObject jsonParam = HIVEUnityPlugin.createParam("Chat", "getChannelsByUser", listener);

            HIVEUnityPlugin.callNative (jsonParam);
        }

        /**
        *  \~korean
        * @brief 사용자 차단 목록 조회<br/>
        * 현재 사용자가 차단한 멤버 목록을 조회한다.<br/>
        *
        * @param listener onGetBlockMembers
        * 
        *  \~english
        * @brief Get blocked member<br/>
        * The current user retrieves the list of members blocked.<br/>
        *
        * @param listener onGetBlockMembers
        *
        *  \~
        * @ingroup Chat
        */
        public static void getBlockMembers(onGetBlockMembers listener) {
            JSONObject jsonParam = HIVEUnityPlugin.createParam("Chat", "getBlockMembers", listener);

            HIVEUnityPlugin.callNative (jsonParam);
        }

        /**
        *  \~korean
        * @brief 멤버 차단<br/>
        * 현재 사용자가 특정 멤버를 차단한다.<br/>
        *
        * @param blockPlayerId 차단할 멤버의 playerId
        * @param listener onBlockMember
        * 
        *  \~english
        * @brief Block member<br/>
        * The current user blocks a specific member.<br/>
        *
        * @param blockPlayerId The playerId of the member the user wants to block
        * @param listener onBlockMember
        *
        *  \~
        * @ingroup Chat
        */
        public static void blockMember(Int64 blockPlayerId, onBlockMember listener) {
            JSONObject jsonParam = HIVEUnityPlugin.createParam("Chat", "blockMember", listener);
            jsonParam.AddField ("blockPlayerId", blockPlayerId);

            HIVEUnityPlugin.callNative (jsonParam);
        }

        /**
        *  \~korean
        * @brief 멤버 차단 해제<br/>
        * 현재 사용자가 차단한 멤버 중 특정 멤버의 차단을 해제한다.<br/>
        *
        * @param blockPlayerId 차단을 해제할 멤버의 playerId
        * @param listener onUnblockMember
        * 
        *  \~english
        * @brief Unblock member<br/>
        * The current user unblocks a specific member.<br/>
        *
        * @param blockPlayerId The playerId of the member the user wants to unblock
        * @param listener onUnblockMember
        *
        *  \~
        * @ingroup Chat
        */
        public static void unblockMember(Int64 blockPlayerId, onUnblockMember listener) {
            JSONObject jsonParam = HIVEUnityPlugin.createParam("Chat", "unblockMember", listener);
            jsonParam.AddField ("blockPlayerId", blockPlayerId);

            HIVEUnityPlugin.callNative (jsonParam);
        }

        public static void translate(TranslateParams param, onTranslate listener) {
            JSONObject jsonParam = HIVEUnityPlugin.createParam("Chat", "translate", listener);
            if (param != null) jsonParam.AddField ("params", param.TOJSON().ToString());

            HIVEUnityPlugin.callNative (jsonParam);
        }

        private static String genUniqueKey() {
            return Guid.NewGuid().ToString("N");
        }


		// \internal
		// \~korean Native 영역에서 호출된 요청을 처리하기 위한 플러그인 내부 코드
		// \~english Plug-in internal code to handle requests invoked from the native code.

        private static void handleEventForConnectionHandler(JSONObject resJsonObject, String eventName)
        {
            String uniqueKey = null;
			resJsonObject.GetField (ref uniqueKey, "uniqueKey");

            if (uniqueKey == null)
            {
                Debug.Log("handleEventForConnectionHandler uniqueKey is null.");
                return;
            }

            if (connectionHandlers.TryGetValue(uniqueKey, out ConnectionHandler connectionHandler))
            {
                if (eventName == "onConnected")
                {
                    connectionHandler.Connect();
                }
                if (eventName == "onReconnectStarted")
                {
                    connectionHandler.ReconnectStarted();
                }
                else if (eventName == "onReconnected")
                {
                    List<String> channelIds = new List<String>();
                    List<String> failChannelIds = new List<String>();
                    JSONObject channelIdsJSONArray = resJsonObject.GetField("channelIds");
                    JSONObject failChannelIdsJSONArray = resJsonObject.GetField("failChannelIds");

                    if (channelIdsJSONArray != null && channelIdsJSONArray.count > 0) {
                        List<JSONObject> channelIdsList = channelIdsJSONArray.list;
                        foreach (JSONObject item in channelIdsList) {
                            channelIds.Add(item.ToString());
                        }
                    }

                    if (failChannelIdsJSONArray != null && failChannelIdsJSONArray.count > 0) {
                        List<JSONObject> failChannelIdsList = failChannelIdsJSONArray.list;
                        foreach (JSONObject item in failChannelIdsList) {
                            failChannelIds.Add(item.ToString());
                        }
                    }
                    connectionHandler.Reconnect(new ResultAPI(resJsonObject.GetField("resultAPI")), channelIds, failChannelIds);
                }
                else if (eventName == "onDisconnected")
                {
                    connectionHandler.Disconnect();
                }
            }
            else
            {
                Debug.Log("handleEventForConnectionHandler connectionHandler not exist");
            }
        }

        private static void handleEventForChannelHandler(JSONObject resJsonObject, String eventName)
        {
            String uniqueKey = null;
			resJsonObject.GetField (ref uniqueKey, "uniqueKey");

            if (uniqueKey == null)
            {
                Debug.Log("handleEventForChannelHandler uniqueKey is null.");
                return;
            }

            if (channelHandlers.TryGetValue(uniqueKey, out ChannelHandler channelHandler))
            {
                JSONObject jsonObject;
                switch (eventName)
                {
                    case "onEnteredMember":
                        jsonObject = resJsonObject.GetField ("member");
                        channelHandler.EnteredMember(new EnteredMember(jsonObject));
                        break;

                    case "onExitedMember":
                        jsonObject = resJsonObject.GetField ("member");
                        channelHandler.ExitedMember(new ExitedMember(jsonObject));
                        break;

                    case "onDeletedChannel":
                        jsonObject = resJsonObject.GetField ("channel");
                        channelHandler.DeletedChannel(new DeletedChannel(jsonObject));
                        break;

                    case "onNoticeMessage":
                        jsonObject = resJsonObject.GetField ("message");
                        channelHandler.NoticeMessage(new ChannelNoticeMessage(jsonObject));
                        break;

                    case "onChannelMessage":
                        jsonObject = resJsonObject.GetField ("message");
                        channelHandler.ChannelMessage(new ChannelMessage(jsonObject));
                        break;

                    case "onAddReaction":
                        jsonObject = resJsonObject.GetField ("reaction");
                        channelHandler.AddReaction(new Reaction(jsonObject));
                        break;

                    case "onRemoveReaction":
                        jsonObject = resJsonObject.GetField ("reaction");
                        channelHandler.RemoveReaction(new Reaction(jsonObject));
                        break;

                    default:
                        break;
                }
            }
            else
            {
                Debug.Log("handleEventForChannelHandler channelHandler not exist");
            }
        }

        private static void handleEventForDirectMessageHandler(JSONObject resJsonObject, String eventName)
        {
            String uniqueKey = null;
			resJsonObject.GetField (ref uniqueKey, "uniqueKey");

            if (uniqueKey == null)
            {
                Debug.Log("handleEventForDirectMessageHandler uniqueKey is null.");
                return;
            }

            if (directMessageHandlers.TryGetValue(uniqueKey, out DirectMessageHandler directMessageHandler))
            {
                if (eventName == "onDirectMessage")
                {
                    JSONObject jsonObject = resJsonObject.GetField("message");
                    directMessageHandler.DirectMessage(new DirectMessage(jsonObject));
                }
            }
            else
            {
                Debug.Log("handleEventForDirectMessageHandler directMessageHandler not exist");
            }
        }

        private static void handleEventForUserHandler(JSONObject resJsonObject, String eventName)
        {
            String uniqueKey = null;
			resJsonObject.GetField (ref uniqueKey, "uniqueKey");

            if (uniqueKey == null)
            {
                Debug.Log("handleEventForUserHandler uniqueKey is null.");
                return;
            }

            if (userHandlers.TryGetValue(uniqueKey, out UserHandler userHandler))
            {
                if (eventName == "onDirectMessage")
                {
                    JSONObject jsonObject = resJsonObject.GetField("message");
                    userHandler.DirectMessage(new DirectMessage(jsonObject));
                }
                else if (eventName == "onNoticeMessage")
                {
                    JSONObject jsonObject = resJsonObject.GetField("message");
                    userHandler.NoticeMessage(new NoticeMessage(jsonObject));
                }
            }
            else
            {
                Debug.Log("handleEventForUserHandler userHandler not exist");
            }
        }

        private static void handleEventForCustomDataHandler(JSONObject resJsonObject, String eventName)
        {
            String uniqueKey = null;
			resJsonObject.GetField (ref uniqueKey, "uniqueKey");

            if (uniqueKey == null)
            {
                Debug.Log("handleEventForCustomDataHandler uniqueKey is null.");
                return;
            }

            if (customDataHandlers.TryGetValue(uniqueKey, out CustomDataHandler customDataHandler))
            {
                if (eventName == "onCustomData")
                {
                    String data = null;
			        resJsonObject.GetField (ref data, "data");
                    customDataHandler.CustomData(data);
                }
            }
            else
            {
                Debug.Log("handleEventForCustomDataHandler customDataHandler not exist");
            }
        }

        private static void handleEvent(JSONObject resJsonObject, String methodName, String eventName)
        {
            if (methodName == "addConnectionListener")
            {
                handleEventForConnectionHandler(resJsonObject, eventName);
            }
            else if (methodName == "addChannelListener")
            {
                handleEventForChannelHandler(resJsonObject, eventName);
            }
            else if (methodName == "addDirectMessageListener")
            {
                handleEventForDirectMessageHandler(resJsonObject, eventName);
            }
            else if (methodName == "addUserListener")
            {
                handleEventForUserHandler(resJsonObject, eventName);
            }
            else if (methodName == "addCustomDataListener")
            {
                handleEventForCustomDataHandler(resJsonObject, eventName);
            }
        }

		public static void executeEngine(JSONObject resJsonObject) {

			String methodName = null;
			resJsonObject.GetField (ref methodName, "method");

            String eventName = null;
            resJsonObject.GetField (ref eventName, "event");

            if (!String.IsNullOrEmpty(eventName))
            {
                handleEvent(resJsonObject, methodName, eventName);
                return;
            }

            if ("sendMessageWithChannelSendMessageParams".Equals(methodName)) {
                String uniqueKey = null;
			    resJsonObject.GetField (ref uniqueKey, "uniqueKey");

                if (channelSendMessageHandlers.TryRemove(uniqueKey, out ChannelSendMessageHandler messageHandler)) {
                    onChannelSendMessage listener = messageHandler.listener;
                    listener (new ResultAPI(resJsonObject.GetField("resultAPI")), messageHandler.param);
                }
                return;
                
            } else if ("sendMessageWithDirectSendMessageParams".Equals(methodName)) {
                String uniqueKey = null;
			    resJsonObject.GetField (ref uniqueKey, "uniqueKey");

                if (directSendMessageHandlers.TryRemove(uniqueKey, out DirectSendMessageHandler messageHandler)) {
                    onDirectSendMessage listener = messageHandler.listener;
                    listener (new ResultAPI(resJsonObject.GetField("resultAPI")), messageHandler.param);
                }
                return;
            }
            

			int handlerId = -1;
			resJsonObject.GetField (ref handlerId, "handler");
			object handler = (object)HIVEUnityPlugin.popHandler (handlerId);

			if (handler == null) return;

            if ("connect".Equals (methodName)) {
                onConnect listener = (onConnect)handler;
                listener (new ResultAPI(resJsonObject.GetField("resultAPI")));
            }
            else if ("reconnect".Equals (methodName)) {
                List<string> channelIds = new List<string>();
                List<string> failChannelIds = new List<string>();
                JSONObject channelIdsJSONArray = resJsonObject.GetField("channelIds");
                JSONObject failChannelIdsJSONArray = resJsonObject.GetField("failChannelIds");

                if (channelIdsJSONArray != null && channelIdsJSONArray.count > 0) {
                    List<JSONObject> channelIdsList = channelIdsJSONArray.list;
                    foreach (JSONObject item in channelIdsList) {
                        channelIds.Add(item.ToString());
                    }
                }

                if (failChannelIdsJSONArray != null && failChannelIdsJSONArray.count > 0) {
                    List<JSONObject> failChannelIdsList = failChannelIdsJSONArray.list;
                    foreach (JSONObject item in failChannelIdsList) {
                        failChannelIds.Add(item.ToString());
                    }
                }

                onReconnect listener = (onReconnect)handler;
                listener (new ResultAPI(resJsonObject.GetField("resultAPI")), channelIds, failChannelIds);
            }
            else if ("disconnect".Equals (methodName)) {
                onDisconnect listener = (onDisconnect)handler;
                listener (new ResultAPI(resJsonObject.GetField("resultAPI")));
            }
            else if ("createChannel".Equals (methodName)) {
                onCreateChannel listener = (onCreateChannel)handler;
                listener (new ResultAPI(resJsonObject.GetField("resultAPI")));
            }
            else if ("getChannels".Equals (methodName)) {
                // parse channels
                List<Channel> channels = new List<Channel>();
                JSONObject channelsJSONArray = resJsonObject.GetField ("channels");
                if (channelsJSONArray != null && channelsJSONArray.count > 0) {
                    
                    List<JSONObject> channelList = channelsJSONArray.list;
                    foreach (JSONObject item in channelList) {
                        Channel channel = new Channel(item);
                        channels.Add(channel);
                    }
                }

                // parse channelPage
                ChannelPage channelPage = null;
                JSONObject channelPageJsonObject = resJsonObject.GetField ("channelPage");
                if (channelPageJsonObject != null) {
                    channelPage = new ChannelPage(channelPageJsonObject);
                }

                onGetChannels listener = (onGetChannels)handler;
                listener (new ResultAPI(resJsonObject.GetField("resultAPI")), channels, channelPage);
            }
            else if ("getChannelInfo".Equals (methodName)) {
                // parse channel
                Channel channel = null;
                JSONObject channelPageJsonObject = resJsonObject.GetField ("channel");
                if (channelPageJsonObject != null) {
                    channel = new Channel(channelPageJsonObject);
                }

                // parse members
                List<Member> members = new List<Member>();
                JSONObject membersJSONArray = resJsonObject.GetField ("members");
                if (membersJSONArray != null && membersJSONArray.count > 0) {
                    
                    List<JSONObject> memberList = membersJSONArray.list;
                    foreach (JSONObject item in memberList) {
                        Member member = new Member(item);
                        members.Add(member);
                    }
                }

                onGetChannelInfo listener = (onGetChannelInfo)handler;
                listener (new ResultAPI(resJsonObject.GetField("resultAPI")), channel, members);
            }
            else if ("getChannelMembers".Equals (methodName)) {
                // parse members
                List<Member> members = new List<Member>();
                JSONObject membersJSONArray = resJsonObject.GetField ("members");
                if (membersJSONArray != null && membersJSONArray.count > 0) {
                    
                    List<JSONObject> memberList = membersJSONArray.list;
                    foreach (JSONObject item in memberList) {
                        Member member = new Member(item);
                        members.Add(member);
                    }
                }

                onGetChannelMembers listener = (onGetChannelMembers)handler;
                listener (new ResultAPI(resJsonObject.GetField("resultAPI")), members);
            }
            else if ("deleteChannel".Equals (methodName)) {
                onDeleteChannel listener = (onDeleteChannel)handler;
                listener (new ResultAPI(resJsonObject.GetField("resultAPI")));
            }
            else if ("enterChannel".Equals (methodName)) {
                onEnterChannel listener = (onEnterChannel)handler;
                listener (new ResultAPI(resJsonObject.GetField("resultAPI")));
            }
            else if ("exitChannel".Equals (methodName)) {
                onEixtChannel listener = (onEixtChannel)handler;
                listener (new ResultAPI(resJsonObject.GetField("resultAPI")));
            }
            else if ("getChannelsByUser".Equals (methodName)) {
                // parse channels
                List<Channel> channels = new List<Channel>();
                JSONObject channelsJSONArray = resJsonObject.GetField ("channels");
                if (channelsJSONArray != null && channelsJSONArray.count > 0) {
                    
                    List<JSONObject> channelList = channelsJSONArray.list;
                    foreach (JSONObject item in channelList) {
                        Channel channel = new Channel(item);
                        channels.Add(channel);
                    }
                }
                
                onGetChannelsByUser listener = (onGetChannelsByUser)handler;
                listener (new ResultAPI(resJsonObject.GetField("resultAPI")), channels);
            }
            else if ("getBlockMembers".Equals (methodName)) {
                // parse blockMembers
                List<BlockMember> blockMembers = new List<BlockMember>();
                JSONObject blockMembersJSONArray = resJsonObject.GetField ("blockMembers");
                if (blockMembersJSONArray != null && blockMembersJSONArray.count > 0) {
                    
                    List<JSONObject> blockMembersList = blockMembersJSONArray.list;
                    foreach (JSONObject item in blockMembersList) {
                        BlockMember blockMember = new BlockMember(item);
                        blockMembers.Add(blockMember);
                    }
                }
                
                onGetBlockMembers listener = (onGetBlockMembers)handler;
                listener (new ResultAPI(resJsonObject.GetField("resultAPI")), blockMembers);
            }
            else if ("blockMember".Equals (methodName)) {
                onBlockMember listener = (onBlockMember)handler;
                listener (new ResultAPI(resJsonObject.GetField("resultAPI")));
            }
            else if ("unblockMember".Equals (methodName)) {
                onUnblockMember listener = (onUnblockMember)handler;
                listener (new ResultAPI(resJsonObject.GetField("resultAPI")));
            }
            else if ("translate".Equals (methodName)) {
                TranslationData data = null;
                
                JSONObject translationsJsonObject = resJsonObject.GetField ("translations");
                if (translationsJsonObject != null) {
                    data = new TranslationData(translationsJsonObject);
                }

                onTranslate listener = (onTranslate)handler;
                listener (new ResultAPI(resJsonObject.GetField("resultAPI")), data);
            }
            else if ("ChannelMessageListQuery".Equals (methodName)) {
                ChannelMessageListQueryResponse queryResponse = null;
                JSONObject responseJsonObject = resJsonObject.GetField ("response");
                if (responseJsonObject != null) {
                    queryResponse = new ChannelMessageListQueryResponse(responseJsonObject);
                }

                onChannelMessageListQuery listener = (onChannelMessageListQuery)handler;
                listener (new ResultAPI(resJsonObject.GetField("resultAPI")), queryResponse);
            }
            else if ("ChannelSetTranslationEnabled".Equals (methodName)) {
                onChannelTranslationSetting listener = (onChannelTranslationSetting)handler;
                listener (new ResultAPI(resJsonObject.GetField("resultAPI")));
            }
            else if ("ChannelAddReaction".Equals (methodName)) {
                ReactionType resultReactionType = ReactionType.None;
                
                String reactionTypeName = "";
                resJsonObject.GetField(ref reactionTypeName, "type");

                if (Enum.TryParse(reactionTypeName, out ReactionType reactionType))
                    resultReactionType = reactionType;

                onReaction listener = (onReaction)handler;
                listener (new ResultAPI(resJsonObject.GetField("resultAPI")), resultReactionType);
            }
            else if ("ChannelRemoveReaction".Equals (methodName)) {
                ReactionType resultReactionType = ReactionType.None;
                
                String reactionTypeName = "";
                resJsonObject.GetField(ref reactionTypeName, "type");

                if (Enum.TryParse(reactionTypeName, out ReactionType reactionType))
                    resultReactionType = reactionType;

                onReaction listener = (onReaction)handler;
                listener (new ResultAPI(resJsonObject.GetField("resultAPI")), resultReactionType);
            }
		}

	}

    /**
    * \~korean 채널 타입
    *
    * \~english Channel Type
    *
    * \~
    * @ingroup Chat
    */
    public enum ChannelType {
        NONE,           ///< \~korean 설정되지 않은 채널 \~english Channel with no type set
        PRIVATE,        ///< \~korean 비밀번호를 입력하여 입장 가능한 채널 \~english Channel accessible by entering a password
        PUBLIC,         ///< \~korean 누구나 입장 가능한 채널 \~english Channel open to everyone
        GROUP           ///< \~korean 특정 유저만 참여하는 채널 (예: 길드 채널) \~english Channel for specific users only (e.g., guild channel)
    }

    /**
    *  \~korean
    * @brief 정렬 기준 타입<br/>
    * 채널 목록 조회시, 전달되는 결과 값의 정렬 기준
    *
    *  \~english
    * @brief Sort Type<br/>
    * Sorting value for the retrieved channel list
    *
    *  \~
    * @ingroup Chat
    */
    public enum SortType {
        None,
        ChannelId,
        ChannelName,
        RegTime
    }

    /**
    *  \~korean
    * @brief 리액션 타입<br/>
    * 채널 메시지 리액션 타입
    *
    *  \~english
    * @brief Reaction Type<br/>
    * Channel message reaction type
    *
    *  \~
    * @ingroup Chat
    */
    public enum ReactionType {
        None,
        Like
    }

    /**
    *  \~korean
    * @brief 채널 메시지 전송 객체<br/>
    * 채널에 메시지를 전송하기 위한 정보를 담고 있는 객체이다.
    *
    *  \~english
    * @brief Channel message sending object<br/>
    * This object contains the information for sending a message to a channel.
    *
    *  \~
    * @ingroup Chat
    */
    public class ChannelSendMessageParams {
        public String channelId;                ///< \~korean 전송 대상 채널 ID \~english Target channel ID
        public String message;                  ///< \~korean 전송할 메시지 내용 \~english The content of the message to be sent
        public String extraData;                ///< \~korean 메시지 추가 데이터. 최대 256 bytes(UTF-8 기반) \~english Message extra data. Up to 256 Bytes(based on UTF-8)
        public String replyMessageId;           ///< \~korean 답글 대상 메시지 ID \~english Reply target message ID
        public List<Int64> mentionedPlayerIds;  ///< \~korean 멘션된 플레이어 ID 목록 \~english List of mentioned player IDs

        public ChannelSendMessageParams() { }

        public ChannelSendMessageParams(String channelId, String message, String extraData = null, String replyMessageId = null, List<Int64> mentionedPlayerIds = null) {
            this.channelId = channelId;
            this.message = message;
            this.extraData = extraData;
            this.replyMessageId = replyMessageId;
            this.mentionedPlayerIds = mentionedPlayerIds;
        }

        public JSONObject TOJSON() {
            JSONObject jsonObject = new JSONObject();

			jsonObject.AddField("channelId", this.channelId);
            jsonObject.AddField("message", this.message);
            jsonObject.AddField("extraData", this.extraData);
            jsonObject.AddField("replyMessageId", this.replyMessageId);
            
            if (mentionedPlayerIds != null && mentionedPlayerIds.Count > 0) 
            {
                JSONObject mentionedPlayersArray = new JSONObject(JSONObject.Type.Array);
                foreach (Int64 playerId in mentionedPlayerIds) 
                {
                    mentionedPlayersArray.Add(playerId);
                }
                jsonObject.AddField("mentionedPlayerIds", mentionedPlayersArray);
            }

			return jsonObject;
        }
    }

    /**
    *  \~korean
    * @brief 1:1 메시지 전송 객체<br/>
    * 특정 사용자에게 메시지를 전송하기 위한 정보를 담고 있는 객체이다.
    *
    *  \~english
    * @brief 1:1 message sending object<br/>
    * This object contains the information for sending a message to a specific user.
    *
    *  \~
    * @ingroup Chat
    */
    public class DirectSendMessageParams {
        public Int64 toPlayerId;        ///< \~korean 대상 사용자 플레이어 ID \~english Target user player ID
        public String message;          ///< \~korean 전송할 메시지 내용 \~english The content of the message to be sent
        public String extraData;        ///< \~korean 메시지 추가 데이터. 최대 256 bytes(UTF-8 기반) \~english Message extra data. Up to 256 Bytes(based on UTF-8)

        public DirectSendMessageParams () { }

        public DirectSendMessageParams(Int64 toPlayerId, String message, String extraData = null) {
            this.toPlayerId = toPlayerId;
            this.message = message;
            this.extraData = extraData;
        }

        public JSONObject TOJSON() {
            JSONObject jsonObject = new JSONObject();

			jsonObject.AddField("toPlayerId", this.toPlayerId);
			jsonObject.AddField("message", this.message);
            jsonObject.AddField("extraData", this.extraData);

			return jsonObject;
        }
    }

    /**
    *  \~korean
    * @brief 채널 생성 객체<br/>
    * 채널을 생성하기 위한 정보를 담고 있는 객체이다.
    *
    *  \~english
    * @brief Channel creation object<br/>
    * This object contains the information for creating a channel.
    *
    *  \~
    * @ingroup Chat
    */
    public class CreateChannelParams {
        public String channelId;        ///< \~korean 채널 ID \~english Channel ID
        public String password;         ///< \~korean 비밀번호 (ChannelType.PRIVATE 채널에만 필수) \~english Password (required only for ChannelType.PRIVATE channels)
        public String channelName;      ///< \~korean 채널 이름 \~english Channel name
        public int maxMemberCount;      ///< \~korean 최대 채널 멤버 수 (최소 2명, 최대 5,000명) \~english Maximum channel members (minimum 2 members, up to 5,000 members)
        public ChannelType type;        ///< \~korean 채널 타입 \~english Channel type
        public bool chatHistoryAllowed; ///< \~korean 채널 메시지 조회 가능 여부 \~english Whether channel messages can be queried

        public CreateChannelParams() { }

        public CreateChannelParams(String channelId, String password, String channelName, int maxMemberCount, ChannelType type, bool chatHistoryAllowed) {
            this.channelId = channelId;
            this.password = password;
            this.channelName = channelName;
            this.maxMemberCount = maxMemberCount;
            this.type = type;
            this.chatHistoryAllowed = chatHistoryAllowed;
        }

        public JSONObject TOJSON() {
            JSONObject jsonObject = new JSONObject();

			jsonObject.AddField("channelId", this.channelId);
			jsonObject.AddField("password", this.password);
            jsonObject.AddField("channelName", this.channelName);
            jsonObject.AddField("maxMemberCount", this.maxMemberCount);
            jsonObject.AddField("type", Enum.GetName(typeof(ChannelType), type));
            jsonObject.AddField("chatHistoryAllowed", this.chatHistoryAllowed);

			return jsonObject;
        }
    }

    /**
    *  \~korean
    * @brief 채널 정보 조회 객체<br/>
    * 채널 정보를 조회하기 위한 객체이다.
    *
    *  \~english
    * @brief Channel information retrieval object<br/>
    * This object contains the information for retrieving channel details.
    *
    *  \~
    * @ingroup Chat
    */
    public class GetChannelsParams {
        public ChannelType type;            ///< \~korean 채널 타입 \~english Channel type
        public String channelId;            ///< \~korean 채널 ID \~english Channel ID
        public String channelName;          ///< \~korean 채널 이름 \~english Channel name
        public SortType sort;               ///< \~korean 정렬 기준 \~english Sort type
        public String pageOrder;            ///< \~korean 정렬 순서 ("ASC", "DESC")(기본값: "DESC") \~english Sort order ("ASC", "DESC") (default is "DESC")
        public int pageSize = 10;           ///< \~korean 페이지당 조회할 채널 수 (최소 10, 최대 100, 기본값: 10) \~english Number of channels to retrieve per page (minimum 10, maximum 100, default is 10)
        public int pageNumber = 1;          ///< \~korean 조회할 페이지 번호 (1부터 시작, 기본값: 1) \~english Page number to retrieve (starts from 1, default is 1)

        public GetChannelsParams() { }

        public GetChannelsParams(ChannelType type, String channelId, String channelName, SortType sort, String pageOrder, int pageSize, int pageNumber) {
            this.type = type;
            this.channelId = channelId;
            this.channelName = channelName;
            this.sort = sort;
            this.pageOrder = pageOrder;
            this.pageSize = pageSize;
            this.pageNumber = pageNumber;
        }

        public JSONObject TOJSON() {
            JSONObject jsonObject = new JSONObject();

            jsonObject.AddField("type", Enum.GetName(typeof(ChannelType), type));
			jsonObject.AddField("channelId", this.channelId);
            jsonObject.AddField("channelName", this.channelName);
            jsonObject.AddField("sort", Enum.GetName(typeof(SortType), sort));
            jsonObject.AddField("pageOrder", this.pageOrder);
            jsonObject.AddField("pageSize", this.pageSize);
            jsonObject.AddField("pageNumber", this.pageNumber);

			return jsonObject;
        }
    }

    /**
    *  \~korean
    * @brief 채널 입장 객체<br/>
    * 채널에 입장하기 위한 정보를 담고 있는 객체이다.
    *
    *  \~english
    * @brief Channel entry object<br/>
    * This object contains the information for entering a channel.
    *
    *  \~
    * @ingroup Chat
    */
    public class EnterChannelParams {
        public String channelId;        ///< \~korean 채널 ID \~english Channel ID
        public String password;         ///< \~korean 비밀번호 (ChannelType.PRIVATE 채널에 요구 됨) \~english (required only for [ChannelType.PRIVATE] channels)

        public EnterChannelParams() { }

        public EnterChannelParams(String channelId, String password) {
            this.channelId = channelId;
            this.password = password;
        }

        public JSONObject TOJSON() {
            JSONObject jsonObject = new JSONObject();

			jsonObject.AddField("channelId", this.channelId);
            jsonObject.AddField("password", this.password);

			return jsonObject;
        }
    }

    /**
    *  \~korean
    * @brief 채널 메시지 조회 객체<br/>
    *
    *  \~english
    * @brief Channel message query object<br/>
    *
    *  \~
    * @ingroup Chat
    */
    public class ChannelMessageListQueryParams {
        public int prevSize;        ///< \~korean 이전 메시지 조회 사이즈 (최소0 ~ 최대 50. 기본값 0) \~english Previous message query size (minimum 0 ~ maximum 50, default 0)
        public int nextSize;        ///< \~korean 이후 메시지 조회 사이즈 (최소0 ~ 최대 50. 기본값 0) \~english Next message query size (minimum 0 ~ maximum 50, default 0)
        public String messageId;    ///< \~korean 조회 기준 메시지 아이디. 만약 null 인 경우, 가장 최신으로 조회 \~english Reference message ID for query. If null, query from the most recent message.
        public String order;        ///< \~korean 정렬 순서(DESC or ASC. 기본 값 DESC) \~english sort order (DESC or ASC. default DESC)

        public ChannelMessageListQueryParams() { }

        public ChannelMessageListQueryParams(int prevSize, int nextSize, String messageId, String order) {
            this.prevSize = prevSize;
            this.nextSize = nextSize;
            this.messageId = messageId;
            this.order = order;
        }

        public JSONObject TOJSON() {
            JSONObject jsonObject = new JSONObject();

			jsonObject.AddField("prevSize", this.prevSize);
            jsonObject.AddField("nextSize", this.nextSize);
            jsonObject.AddField("messageId", this.messageId);
            jsonObject.AddField("order", this.order);

			return jsonObject;
        }
    }

    /**
    *  \~korean
    * @brief 채널 메시지 조회 응답 객체<br/>
    *
    *  \~english
    * @brief Channel message query response object<br/>
    *
    *  \~
    * @ingroup Chat
    */
    public class ChannelMessageListQueryResponse {
        public bool hasNext;
        public String nextMessageId;
        public bool hasPrev;
        public String prevMessageId;
        public List<ChannelMessage> content;

        public ChannelMessageListQueryResponse() { }

        public ChannelMessageListQueryResponse(JSONObject jsonObject) {
            if (jsonObject == null || jsonObject.count <= 0)
                return;

            jsonObject.GetField(ref hasNext, "hasNext");
            jsonObject.GetField(ref nextMessageId, "nextMessageId");
            jsonObject.GetField(ref hasPrev, "hasPrev");
            jsonObject.GetField(ref prevMessageId, "prevMessageId");

            List<ChannelMessage> content = new List<ChannelMessage>();
            JSONObject contentJsonObject = jsonObject.GetField("content");
            if (contentJsonObject != null && contentJsonObject.count > 0)
            {
                List<JSONObject> contentJsonArray = contentJsonObject.list;
                foreach (JSONObject item in contentJsonArray)
                {
                    ChannelMessage channelMessage = new ChannelMessage(item);
                    content.Add(channelMessage);
                }
            }
            this.content = content;
        }

        public JSONObject TOJSON() {
            JSONObject jsonObject = new JSONObject();

            jsonObject.AddField("hasNext", this.hasNext);
            jsonObject.AddField("nextMessageId", this.nextMessageId);
            jsonObject.AddField("hasPrev", this.hasPrev);
            jsonObject.AddField("prevMessageId", this.prevMessageId);

            JSONObject contentArray = new JSONObject();
            if (content != null) {
                foreach (ChannelMessage message in content) {
                    if (message != null)
                        contentArray.Add(message.TOJSON());
                }
            }
            jsonObject.AddField("content", contentArray);

			return jsonObject;
        }
        
    }

    /**
    *  \~korean
    * @brief 번역 요청 객체<br/>
    *
    *  \~english
    * @brief Translation request object<br/>
    *
    *  \~
    * @ingroup Chat
    */
    public class TranslateParams {
        public String message;                  ///< \~korean 원문 메시지 \~english origin message
        public String sourceLanguage = "auto";  ///< \~korean 원문 메시지 언어 코드(기본값 "auto") \~english Language code of the original message (default. "auto")
        public List<String> targetLanguage;     ///< \~korean 대상 언어코드 \~english Target language code(s) for translation

        public TranslateParams() { }

        public TranslateParams(String message, String sourceLanguage, List<String> targetLanguage) {
            this.message = message;
            this.sourceLanguage = sourceLanguage;
            this.targetLanguage = targetLanguage;
        }

        public JSONObject TOJSON() {
            JSONObject jsonObject = new JSONObject();

			jsonObject.AddField("message", this.message);
            jsonObject.AddField("sourceLanguage", this.sourceLanguage);

            JSONObject targetArray = new JSONObject();
            if (this.targetLanguage != null) {
                foreach (String lang in this.targetLanguage) {
                    targetArray.Add(lang);
                }
            }
            jsonObject.AddField("targetLanguage", targetArray);

			return jsonObject;
        }
    }

    public class TranslationData {
        public Dictionary<String, String> translations = new Dictionary<String, String>();

        public TranslationData(Dictionary<String, String> translations) {
            this.translations = translations;
        }

        public TranslationData(JSONObject jsonObject) {
            if (jsonObject == null || jsonObject.count <= 0)
                return;

            foreach (String key in jsonObject.keys) {
                String _value = "";
                jsonObject.GetField(ref _value, key);
                translations[key] = _value;
            }
        }

        public JSONObject TOJSON() {
            JSONObject jsonObject = new JSONObject();
            foreach (KeyValuePair<String, String> entry in translations) {
                jsonObject.AddField(entry.Key, entry.Value);
            }
			return jsonObject;
        }
        
    }

    /**
    *  \~korean
    * @brief 채널 정보 조회 시 반환되는 객체<br/>
    * 채널 정보를 조회할 때 반환되는 객체이다.
    *
    *  \~english
    * @brief Object returned when retrieving channel information<br/>
    * This object is returned when retrieving information about a channel.
    *
    *  \~
    * @ingroup Chat
    */
    public class Channel {
        public String channelId;            ///< \~korean 채널 ID \~english Channel ID
        public ChannelType type;            ///< \~korean 채널 타입 \~english Channel Type
        public String owner;                ///< \~korean 채널 소유자 \~english Channel owner
        public String channelName;          ///< \~korean 채널 이름 \~english Channel name
        public int memberCount;             ///< \~korean 현재 채널 참여자 수 \~english Current number of members in the channel
        public int maxMemberCount;          ///< \~korean 최대 채널 참여자 수 \~english Maximum number of channel members
        public String regTime;              ///< \~korean 채널 생성 시간 (UTC+0, yyyy-MM-dd'T'HH:mm:ss.SSSZ 포맷) \~english Channel creation timestamp (UTC+0, in the format yyyy-MM-dd'T'HH:mm:ss.SSSZ)
        public Int64 regTimeMillis;         ///< \~korean 채널 생성 시간 유닉스타임 (UTC+0) \~english Channel creation UnixTime (UTC+0)
        public bool chatHistoryAllowed;     ///< \~korean 채널 메시지 조회 가능 여부 \~english Whether channel messages can be queried

        public Channel(String channelId, ChannelType type, String owner, String channelName, int memberCount, int maxMemberCount, String regTime, Int64 regTimeMillis, bool chatHistoryAllowed) {
            this.channelId = channelId;
            this.type = type;
            this.owner = owner;
            this.channelName = channelName;
            this.memberCount = memberCount;
            this.maxMemberCount = maxMemberCount;
            this.regTime = regTime;
            this.regTimeMillis = regTimeMillis;
            this.chatHistoryAllowed = chatHistoryAllowed;
        }

        public Channel(JSONObject jsonObject) {
            if (jsonObject == null || jsonObject.count <= 0)
                return;

			jsonObject.GetField(ref channelId, "channelId");

            String typeName = "";
            jsonObject.GetField(ref typeName, "type");
            if (Enum.TryParse(typeName, out ChannelType type)) {
                this.type = type;
            }
			
            jsonObject.GetField(ref owner, "owner");
            jsonObject.GetField(ref channelName, "channelName");
            jsonObject.GetField(ref memberCount, "memberCount");
            jsonObject.GetField(ref maxMemberCount, "maxMemberCount");
            jsonObject.GetField(ref regTime, "regTime");
            jsonObject.GetField(ref regTimeMillis, "regTimeMillis");
            jsonObject.GetField(ref chatHistoryAllowed, "chatHistoryAllowed");
        }

        public JSONObject TOJSON() {
            JSONObject jsonObject = new JSONObject();

            jsonObject.AddField("channelId", this.channelId);
            jsonObject.AddField("type", Enum.GetName(typeof(ChannelType), type));
            jsonObject.AddField("owner", this.owner);
            jsonObject.AddField("channelName", this.channelName);
            jsonObject.AddField("memberCount", this.memberCount);
            jsonObject.AddField("maxMemberCount", this.maxMemberCount);
            jsonObject.AddField("regTime", this.regTime);
            jsonObject.AddField("regTimeMillis", this.regTimeMillis);
            jsonObject.AddField("chatHistoryAllowed", this.chatHistoryAllowed);

			return jsonObject;
        }

        public void query(ChannelMessageListQueryParams param, Chat.onChannelMessageListQuery listener) {
            JSONObject jsonParam = HIVEUnityPlugin.createParam("Chat", "ChannelMessageListQuery", listener);
            jsonParam.AddField("channel", this.TOJSON().ToString());
            if(param != null) jsonParam.AddField ("params", param.TOJSON().ToString());
            HIVEUnityPlugin.callNative (jsonParam);
        }

        public void setTranslationEnabled(bool isEnabled, Chat.onChannelTranslationSetting listener) {
            JSONObject jsonParam = HIVEUnityPlugin.createParam("Chat", "ChannelSetTranslationEnabled", listener);
            jsonParam.AddField("channel", this.TOJSON().ToString());
            jsonParam.AddField ("isEnabled", isEnabled);
            HIVEUnityPlugin.callNative (jsonParam);
        }

        public void addReaction(String messageId, ReactionType reactionType, Chat.onReaction listener) {
            JSONObject jsonParam = HIVEUnityPlugin.createParam("Chat", "ChannelAddReaction", listener);
            jsonParam.AddField("channel", this.TOJSON().ToString());
            jsonParam.AddField("messageId", messageId);
            jsonParam.AddField("type", Enum.GetName(typeof(ReactionType), reactionType));
            HIVEUnityPlugin.callNative (jsonParam);
        }

        public void removeReaction(String messageId, ReactionType reactionType, Chat.onReaction listener) {
            JSONObject jsonParam = HIVEUnityPlugin.createParam("Chat", "ChannelRemoveReaction", listener);
            jsonParam.AddField("channel", this.TOJSON().ToString());
            jsonParam.AddField("messageId", messageId);
            jsonParam.AddField("type", Enum.GetName(typeof(ReactionType), reactionType));
            HIVEUnityPlugin.callNative (jsonParam);
        }
    }

    /**
    *  \~korean
    * @brief 채널 정보 조회시 반환되는 채널 페이지 객체<br/>
    * 채널 정보를 조회할 때 반환되는 채널 페이지 객체이다.
    *
    *  \~english
    * @brief Channel page object returned when retrieving channel information<br/>
    * This object represents a page of channels returned when retrieving channel information.
    *
    *  \~
    * @ingroup Chat
    */
    public class ChannelPage {
        public int size;                ///< \~korean 페이지당 요소 개수 \~english Number of elements per page
        public int currentPage;         ///< \~korean 현재 페이지 번호 \~english Current page number
        public int totalElements;       ///< \~korean 전체 요소 개수 \~english Total number of elements
        public int totalPages;          ///< \~korean 전체 페이지 개수 \~english Total number of pages

        public ChannelPage(int size, int currentPage, int totalElements, int totalPages) {
            this.size = size;
            this.currentPage = currentPage;
            this.totalElements = totalElements;
            this.totalPages = totalPages;
        }

        public ChannelPage(JSONObject jsonObject) {
            if (jsonObject == null || jsonObject.count <= 0)
                return;

            jsonObject.GetField(ref size, "size");
            jsonObject.GetField(ref currentPage, "currentPage");
            jsonObject.GetField(ref totalElements, "totalElements");
            jsonObject.GetField(ref totalPages, "totalPages");
        }

        public JSONObject TOJSON() {
            JSONObject jsonObject = new JSONObject();

            jsonObject.AddField("size", this.size);
            jsonObject.AddField("currentPage", this.currentPage);
            jsonObject.AddField("totalElements", this.totalElements);
            jsonObject.AddField("totalPages", this.totalPages);

			return jsonObject;
        }
    }

    /**
    *  \~korean
    * @brief 멤버 및 채널 정보 조회시 반환되는 멤버 객체<br/>
    * 멤버 및 채널 정보를 조회할 때 반환되는 멤버 객체이다.
    *
    *  \~english
    * @brief Member object returned when retrieving member and channel information<br/>
    * This object represents a member returned when retrieving member and channel information.
    *
    *  \~
    * @ingroup Chat
    */
    public class Member {
        public Int64 playerId;          ///< \~korean 플레이어 ID \~english Player ID
        public String connectedTime;    ///< \~korean 연결 시간 (UTC+0, yyyy-MM-dd'T'HH:mm:ss.SSSZ 포맷) \~english Connection timestamp (UTC+0, in the format yyyy-MM-dd'T'HH:mm:ss.SSSZ)
        public Int64 connectedTimeMillis; ///< \~korean 연결 시간 UnixTime (UTC+0) \~english Connection UnixTime (UTC+0)

        public Member(Int64 playerId, String connectedTime, Int64 connectedTimeMillis) {
            this.playerId = playerId;
            this.connectedTime = connectedTime;
            this.connectedTimeMillis = connectedTimeMillis;
        }

        public Member(JSONObject jsonObject) {
            if (jsonObject == null || jsonObject.count <= 0)
                return;

            jsonObject.GetField(ref playerId, "playerId");
            jsonObject.GetField(ref connectedTime, "connectedTime");
            jsonObject.GetField(ref connectedTimeMillis, "connectedTimeMillis");
        }

        public JSONObject TOJSON() {
            JSONObject jsonObject = new JSONObject();

            jsonObject.AddField("playerId", this.playerId);
            jsonObject.AddField("connectedTime", this.connectedTime);
            jsonObject.AddField("connectedTimeMillis", this.connectedTimeMillis);

			return jsonObject;
        }
    }

    /**
    *  \~korean
    * @brief 차단 멤버 조회시 반환되는 차단 멤버 객체<br/>
    * 차단된 멤버를 조회할 때 반환되는 차단 멤버 객체이다.
    *
    *  \~english
    * @brief Blocked member object returned when retrieving blocked members<br/>
    * This object represents a blocked member returned when retrieving blocked members.
    *
    *  \~
    * @ingroup Chat
    */
    public class BlockMember {
        public Int64 playerId;              ///< \~korean 플레이어 ID \~english Player ID
        public String blockedTime;          ///< \~korean 차단 시간 (UTC+0, yyyy-MM-dd'T'HH:mm:ss.SSSZ 포맷) \~english Timestamp of when the member was blocked (UTC+0, in the format yyyy-MM-dd'T'HH:mm:ss.SSSZ)
        public Int64 blockedTimeMillis;     ///< \~korean 차단 시간 UnixTime (UTC+0) \~english UnixTime of when the member was blocked (UTC+0)

        public BlockMember(Int64 playerId, String blockedTime, Int64 blockedTimeMillis) {
            this.playerId = playerId;
            this.blockedTime = blockedTime;
            this.blockedTimeMillis = blockedTimeMillis;
        }

        public BlockMember(JSONObject jsonObject) {
            if (jsonObject == null || jsonObject.count <= 0)
                return;

            jsonObject.GetField(ref playerId, "playerId");
            jsonObject.GetField(ref blockedTime, "blockedTime");
            jsonObject.GetField(ref blockedTimeMillis, "blockedTimeMillis");
        }

        public JSONObject TOJSON() {
            JSONObject jsonObject = new JSONObject();

            jsonObject.AddField("playerId", this.playerId);
            jsonObject.AddField("blockedTime", this.blockedTime);
            jsonObject.AddField("blockedTimeMillis", this.blockedTimeMillis);

			return jsonObject;
        }
    }

    /**
    *  \~korean
    * @brief 채널에 입장한 멤버 객체<br/>
    * 채널에 입장한 멤버 정보로 ChannelHandler.onEnteredMember 이벤트를 통해 전달 받는다.
    *
    *  \~english
    * @brief Member object who entered the channel<br/>
    * The information of the member who entered the channel is received through the ChannelHandler.onEnteredMember event.
    *
    *  \~
    * @ingroup Chat
    */
    public class EnteredMember {
        public String channelId;            ///< \~korean 채널 ID \~english Channel ID
        public Int64 playerId;              ///< \~korean 플레이어 ID \~english Player ID
        public String timestamp;            ///< \~korean 입장 시간 (UTC+0, yyyy-MM-dd'T'HH:mm:ss.SSSZ 포맷) \~english Entered timestamp (UTC+0, in the format yyyy-MM-dd'T'HH:mm:ss.SSSZ)
        public Int64 timestampMillis;      ///< \~korean 입장 시간 유닉스타임 (UTC+0,) \~english Entered UnixTime (UTC+0, in the format unixtime)

        public EnteredMember(String channelId, Int64 playerId, String timestamp, Int64 timestampMillis) {
            this.channelId = channelId;
            this.playerId = playerId;
            this.timestamp = timestamp;
            this.timestampMillis = timestampMillis;
        }

        public EnteredMember(JSONObject jsonObject) {
            if (jsonObject == null || jsonObject.count <= 0)
                return;

            jsonObject.GetField(ref channelId, "channelId");
            jsonObject.GetField(ref playerId, "playerId");
            jsonObject.GetField(ref timestamp, "timestamp");
            jsonObject.GetField(ref timestampMillis, "timestampMillis");
        }

        public JSONObject TOJSON() {
            JSONObject jsonObject = new JSONObject();

            jsonObject.AddField("channelId", this.channelId);
            jsonObject.AddField("playerId", this.playerId);
            jsonObject.AddField("timestamp", this.timestamp);
            jsonObject.AddField("timestampMillis", this.timestampMillis);

			return jsonObject;
        }
    }

    /**
    *  \~korean
    * @brief 채널에서 퇴장한 멤버 객체<br/>
    * 채널에서 퇴장한 멤버 정보는 ChannelHandler.onExitedMember 이벤트를 통해 전달 받는다.
    *
    *  \~english
    * @brief Member object who exited the channel<br/>
    * The information of the member who exited the channel is received through the ChannelHandler.onExitedMember event.
    *
    *  \~
    * @ingroup Chat
    */
    public class ExitedMember {
        public String channelId;            ///< \~korean 채널 ID \~english Channel ID
        public Int64 playerId;              ///< \~korean 플레이어 ID \~english Player ID
        public String timestamp;            ///< \~korean 퇴장 시간 (UTC+0, yyyy-MM-dd'T'HH:mm:ss.SSSZ 포맷) \~english Exited timestamp (UTC+0, in the format yyyy-MM-dd'T'HH:mm:ss.SSSZ)
        public Int64 timestampMillis;      ///< \~korean 퇴장 시간 유닉스타임 (UTC+0) \~english Exited UnixTime (UTC+0)

        public ExitedMember(String channelId, Int64 playerId, String timestamp, Int64 timestampMillis) {
            this.channelId = channelId;
            this.playerId = playerId;
            this.timestamp = timestamp;
            this.timestampMillis = timestampMillis;
        }

        public ExitedMember(JSONObject jsonObject) {
            if (jsonObject == null || jsonObject.count <= 0)
                return;

            jsonObject.GetField(ref channelId, "channelId");
            jsonObject.GetField(ref playerId, "playerId");
            jsonObject.GetField(ref timestamp, "timestamp");
            jsonObject.GetField(ref timestampMillis, "timestampMillis");
        }

        public JSONObject TOJSON() {
            JSONObject jsonObject = new JSONObject();

            jsonObject.AddField("channelId", this.channelId);
            jsonObject.AddField("playerId", this.playerId);
            jsonObject.AddField("timestamp", this.timestamp);
            jsonObject.AddField("timestampMillis", this.timestampMillis);

			return jsonObject;
        }
    }

    /**
    *  \~korean
    * @brief 삭제된 채널 정보 객체<br/>
    * 삭제된 채널의 정보는 ChannelHandler.onDeletedChannel 이벤트를 통해 전달된다.
    *
    *  \~english
    * @brief Deleted channel information object<br/>
    * The information of the deleted channel is delivered through the ChannelHandler.onDeletedChannel event.
    *
    *  \~
    * @ingroup Chat
    */
    public class DeletedChannel {
        public String channelId;            ///< \~korean 채널 ID \~english Channel ID
        public String timestamp;            ///< \~korean 삭제된 시간 (UTC+0, yyyy-MM-dd'T'HH:mm:ss.SSSZ 포맷) \~english Deleted timestamp (UTC+0, in the format yyyy-MM-dd'T'HH:mm:ss.SSSZ)
        public Int64 timestampMillis;      ///< \~korean 삭제된 시간 유닉스타임 (UTC+0, unixtime) \~english Deleted UnixTime (UTC+0)

        public DeletedChannel(String channelId, String timestamp, Int64 timestampMillis) {
            this.channelId = channelId;
            this.timestamp = timestamp;
            this.timestampMillis = timestampMillis;
        }

        public DeletedChannel(JSONObject jsonObject) {
            if (jsonObject == null || jsonObject.count <= 0)
                return;

            jsonObject.GetField(ref channelId, "channelId");
            jsonObject.GetField(ref timestamp, "timestamp");
            jsonObject.GetField(ref timestampMillis, "timestampMillis");
        }

        public JSONObject TOJSON() {
            JSONObject jsonObject = new JSONObject();

            jsonObject.AddField("channelId", this.channelId);
            jsonObject.AddField("timestamp", this.timestamp);
            jsonObject.AddField("timestampMillis", this.timestampMillis);

			return jsonObject;
        }
    }

    /**
    *  \~korean
    * @brief 채널 공지 메시지 객체<br/>
    * 채널 공지 메시지 정보는 ChannelHandler.onNoticeMessage 이벤트를 통해 전달된다.
    *
    *  \~english
    * @brief Channel notice message object<br/>
    * The channel notice message information is delivered through the ChannelHandler.onNoticeMessage event.
    *
    *  \~
    * @ingroup Chat
    */
    public class ChannelNoticeMessage {
        public String channelId;            ///< \~korean 채널 ID \~english Channel ID
        public String from;                 ///< \~korean 메시지 발송자 \~english Message sender
        public String message;              ///< \~korean 공지 메시지 내용 \~english Notice message content
        public String timestamp;            ///< \~korean 공지 메시지 발송 시간 (UTC+0, yyyy-MM-dd'T'HH:mm:ss.SSSZ 포맷) \~english Timestamp when the notice message was sent (UTC+0, in the format yyyy-MM-dd'T'HH:mm:ss.SSSZ)
        public Int64 timestampMillis;      ///< \~korean  공지 메시지 발송 시간 타임스탬프 (UTC+0,) \~english Timestamp when the notice message was sent (UTC+0, in the format unixtime)

        public ChannelNoticeMessage(String channelId, String from, String message, String timestamp, Int64 timestampMillis) {
            this.channelId = channelId;
            this.from = from;
            this.message = message;
            this.timestamp = timestamp;
            this.timestampMillis = timestampMillis;
        }

        public ChannelNoticeMessage(JSONObject jsonObject) {
            if (jsonObject == null || jsonObject.count <= 0)
                return;

            jsonObject.GetField(ref channelId, "channelId");
            jsonObject.GetField(ref from, "from");
            jsonObject.GetField(ref message, "message");
            jsonObject.GetField(ref timestamp, "timestamp");
            jsonObject.GetField(ref timestampMillis, "timestampMillis");
        }

        public JSONObject TOJSON() {
            JSONObject jsonObject = new JSONObject();

            jsonObject.AddField("channelId", this.channelId);
            jsonObject.AddField("from", this.from);
            jsonObject.AddField("message", this.message);
            jsonObject.AddField("timestamp", this.timestamp);
            jsonObject.AddField("timestampMillis", this.timestampMillis);

			return jsonObject;
        }
    }

    /**
    *  \~korean
    * @brief 채널 메시지 객체<br/>
    * 채널 메시지 정보는 ChannelHandler.onChannelMessage 이벤트를 통해 전달된다.
    *
    *  \~english
    * @brief Channel message object<br/>
    * The channel message information is delivered through the ChannelHandler.onChannelMessage event.
    *
    *  \~
    * @ingroup Chat
    */
    public class ChannelMessage {
        public String messageId;        ///< \~korean 메시지 아이디 \~english Message ID
        public Int64 from;              ///< \~korean 메시지 발송자 \~english Message sender
        public String extraData;        ///< \~korean 발송자와 관련된 추가 데이터 \~english Extra data related to the sender
        public String to;               ///< \~korean 수신 채널 (채널 ID) \~english Receiving channel (channel ID)
        public String message;          ///< \~korean 메시지 내용 \~english Message content
        public bool translated;         ///< \~korean 메시지 번역 여부 \~english Whether to translate the message
        public String translatedMessage;///< \~korean 번역 메시지 \~english Translated Message content
        public String timestamp;        ///< \~korean 메시지 발송 시간 (UTC+0, yyyy-MM-dd'T'HH:mm:ss.SSSZ 포맷) \~english Timestamp when the message was sent (UTC+0, in the format yyyy-MM-dd'T'HH:mm:ss.SSSZ)
        public Int64 timestampMillis;   ///< \~korean 메시지 발송 시간 UnixTime (밀리초) \~english UnixTime when the message was sent (milliseconds)
        public String replyMessageId;   ///< \~korean 답글 대상 메시지 아이디 \~english Reply target message ID
        public String replyMessage;     ///< \~korean 답글 메시지 \~english Reply message content
        public String replyExtraData;   ///< \~korean 답글 추가 데이터 \~english Extra data of the reply message
        public List<Int64> mentionedPlayerIds; ///< \~korean 멘션된 플레이어 ID 목록 \~english List of mentioned player IDs
        public Dictionary<ReactionType, List<Int64>> reactions; ///< \~korean 리액션 정보 \~english Reaction information

        public ChannelMessage() { }

        public ChannelMessage(JSONObject jsonObject) {
            if (jsonObject == null || jsonObject.count <= 0)
                return;

            jsonObject.GetField(ref messageId, "messageId");
            jsonObject.GetField(ref from, "from");
            jsonObject.GetField(ref extraData, "extraData");
            jsonObject.GetField(ref to, "to");
            jsonObject.GetField(ref message, "message");
            jsonObject.GetField(ref translated, "translated");
            jsonObject.GetField(ref translatedMessage, "translatedMessage");
            jsonObject.GetField(ref timestamp, "timestamp");
            jsonObject.GetField(ref timestampMillis, "timestampMillis");
            jsonObject.GetField(ref replyMessageId, "replyMessageId");
            jsonObject.GetField(ref replyMessage, "replyMessage");
            jsonObject.GetField(ref replyExtraData, "replyExtraData");

            JSONObject mentionedPlayerJsonArray = jsonObject.GetField("mentionedPlayerIds");
            if (mentionedPlayerJsonArray != null && mentionedPlayerJsonArray.isArray)
            {
                List<Int64> _mentionedPlayerIds = new List<Int64>();

                for (int i = 0; i < mentionedPlayerJsonArray.count; i++)
                {
                    JSONObject element = mentionedPlayerJsonArray[i];
                    if (element != null && element.isNumber)
                    {
                        _mentionedPlayerIds.Add(element.longValue);
                    }
                }
                mentionedPlayerIds = _mentionedPlayerIds;
            }

            JSONObject reactionsJsonObject = jsonObject.GetField("reactions");
            if (reactionsJsonObject != null)
            {
                reactions = new Dictionary<ReactionType, List<Int64>>();

                foreach (String key in reactionsJsonObject.keys)
                {
                    if (System.Enum.TryParse<ReactionType>(key, out ReactionType reactionType))
                    {
                        JSONObject reactionArray = reactionsJsonObject.GetField(key);
                        if (reactionArray != null && reactionArray.isArray)
                        {
                            List<Int64> playerIds = new List<Int64>();
                            
                            for (int i = 0; i < reactionArray.count; i++)
                            {
                                JSONObject element = reactionArray[i];
                                if (element != null && element.isNumber)
                                {
                                    playerIds.Add(element.longValue);
                                }
                            }
                            
                            reactions[reactionType] = playerIds;
                        }
                    }
                }
            }
        }

        public JSONObject TOJSON() {
            JSONObject jsonObject = new JSONObject();

            jsonObject.AddField("messageId", this.messageId);
            jsonObject.AddField("from", this.from);
            jsonObject.AddField("extraData", this.extraData);
            jsonObject.AddField("to", this.to);
            jsonObject.AddField("message", this.message);
            jsonObject.AddField("translated", this.translated);
            jsonObject.AddField("translatedMessage", this.translatedMessage);
            jsonObject.AddField("timestamp", this.timestamp);
            jsonObject.AddField("timestampMillis", this.timestampMillis);
            jsonObject.AddField("replyMessageId", this.replyMessageId);
            jsonObject.AddField("replyMessage", this.replyMessage);
            jsonObject.AddField("replyExtraData", this.replyExtraData);
            
            if (mentionedPlayerIds != null && mentionedPlayerIds.Count > 0) 
            {
                JSONObject mentionedPlayersArray = new JSONObject(JSONObject.Type.Array);
                foreach (Int64 playerId in mentionedPlayerIds) 
                {
                    mentionedPlayersArray.Add(playerId);
                }
                jsonObject.AddField("mentionedPlayerIds", mentionedPlayersArray);
            }

            JSONObject reactionsJson = ConvertReactionsToJson();
            if (reactionsJson != null)
            {
                jsonObject.AddField("reactions", reactionsJson);
            }

			return jsonObject;
        }

        private JSONObject ConvertReactionsToJson() {
            if (reactions == null || reactions.Count == 0)
                return null;

            JSONObject reactionsJson = new JSONObject();

            foreach (var kvp in reactions) {
                String reactionType = Enum.GetName(typeof(ReactionType), kvp.Key);

                JSONObject reactionArray = new JSONObject(JSONObject.Type.Array);
                if (kvp.Value != null)
                {
                    foreach (Int64 playerId in kvp.Value)
                    {
                        reactionArray.Add(playerId);
                    }
                }
                
                reactionsJson.AddField(reactionType, reactionArray);
            }

            return reactionsJson;
        }
    }

    /**
    *  \~korean
    * @brief 1:1 메시지 객체<br/>
    * 1:1 메시지 정보는 [DirectMessageListener.onDirectMessage] 이벤트를 통해 전달된다.
    *
    *  \~english
    * @brief Direct message object<br/>
    * The direct message information is delivered through the [DirectMessageListener.onDirectMessage] event.
    *
    *  \~
    * @ingroup Chat
    */
    public class DirectMessage {
        public String messageId;        ///< \~korean 메시지 아이디 \~english Message ID
        public Int64 from;              ///< \~korean 메시지 발송자 플레이어 ID \~english Message sender player ID
        public String extraData;        ///< \~korean 발송자와 관련된 추가 데이터 \~english Extra data related to the sender
        public Int64 to;                ///< \~korean 수신 사용자 (플레이어 ID) \~english Receiving user (player ID)
        public String message;          ///< \~korean 메시지 내용 \~english Message content
        public String timestamp;        ///< \~korean 메시지 발송 시간 (UTC+0, yyyy-MM-dd'T'HH:mm:ss.SSSZ 포맷) \~english Timestamp when the message was sent (UTC+0, in the format yyyy-MM-dd'T'HH:mm:ss.SSSZ)
        public Int64 timestampMillis;   ///< \~korean 메시지 발송 시간 UnixTime (밀리초) \~english UnixTime when the message was sent (milliseconds)

        public DirectMessage() { }

        public DirectMessage(JSONObject jsonObject) {
            if (jsonObject == null || jsonObject.count <= 0)
                return;

            jsonObject.GetField(ref messageId, "messageId");
            jsonObject.GetField(ref from, "from");
            jsonObject.GetField(ref extraData, "extraData");
            jsonObject.GetField(ref to, "to");
            jsonObject.GetField(ref message, "message");
            jsonObject.GetField(ref timestamp, "timestamp");
            jsonObject.GetField(ref timestampMillis, "timestampMillis");
        }

        public JSONObject TOJSON() {
            JSONObject jsonObject = new JSONObject();

            jsonObject.AddField("messageId", this.messageId);
            jsonObject.AddField("from", this.from);
            jsonObject.AddField("extraData", this.extraData);
            jsonObject.AddField("to", this.to);
            jsonObject.AddField("message", this.message);
            jsonObject.AddField("timestamp", this.timestamp);
            jsonObject.AddField("timestampMillis", this.timestampMillis);

			return jsonObject;
        }
    }

    /**
    *  \~korean
    * @brief 사용자 공지 메시지 객체<br/>
    * 사용자 공지 메시지 정보는 UserHandler.onNoticeMessage 이벤트를 통해 전달된다.
    *
    *  \~english
    * @brief User notice message object<br/>
    * The user notice message information is delivered through the UserHandler.onNoticeMessage event.
    *
    *  \~
    * @ingroup Chat
    */
    public class NoticeMessage {
        public String from;                 ///< \~korean 메시지 발송자 \~english Message sender
        public String message;              ///< \~korean 공지 메시지 내용 \~english Notice message content
        public String timestamp;            ///< \~korean 공지 메시지 발송 시간 (UTC+0, yyyy-MM-dd'T'HH:mm:ss.SSSZ 포맷) \~english Timestamp when the notice message was sent (UTC+0, in the format yyyy-MM-dd'T'HH:mm:ss.SSSZ)
        public Int64 timestampMillis;       ///< \~korean  공지 메시지 발송 시간 타임스탬프 (UTC+0,) \~english Timestamp when the notice message was sent (UTC+0, in the format unixtime)

        public NoticeMessage(String from, String message, String timestamp, Int64 timestampMillis) {
            this.from = from;
            this.message = message;
            this.timestamp = timestamp;
            this.timestampMillis = timestampMillis;
        }

        public NoticeMessage(JSONObject jsonObject) {
            if (jsonObject == null || jsonObject.count <= 0)
                return;

            jsonObject.GetField(ref from, "from");
            jsonObject.GetField(ref message, "message");
            jsonObject.GetField(ref timestamp, "timestamp");
            jsonObject.GetField(ref timestampMillis, "timestampMillis");
        }

        public JSONObject TOJSON() {
            JSONObject jsonObject = new JSONObject();

            jsonObject.AddField("from", this.from);
            jsonObject.AddField("message", this.message);
            jsonObject.AddField("timestamp", this.timestamp);
            jsonObject.AddField("timestampMillis", this.timestampMillis);

			return jsonObject;
        }
    }

    public class Reaction {
        public String channelId;
        public String messageId;
        public Int64 playerId;
        public ReactionType reactionType;

        public Reaction() { }

        public Reaction(JSONObject jsonObject) {
            if (jsonObject == null || jsonObject.count <= 0)
                return;

            jsonObject.GetField(ref channelId, "channelId");
            jsonObject.GetField(ref messageId, "messageId");
            jsonObject.GetField(ref playerId, "playerId");
            
            String reactionTypeName = "";
            jsonObject.GetField(ref reactionTypeName, "type");
            if (Enum.TryParse(reactionTypeName, out ReactionType resultReactionType))
                reactionType = resultReactionType;
        }

        public JSONObject TOJSON() {
            JSONObject jsonObject = new JSONObject();

            jsonObject.AddField("channelId", this.channelId);
            jsonObject.AddField("messageId", this.messageId);
            jsonObject.AddField("playerId", this.playerId);
            jsonObject.AddField("reactionType", Enum.GetName(typeof(ReactionType), reactionType));

			return jsonObject;
        }
    }

    /**
    *  \~korean
    * @brief 연결 상태 변화에 대한 콜백을 제공하는 리스너<br/>
    * 이 클래스는 연결 성공 및 연결 실패 시 발생하는 이벤트를 처리합니다.
    *
    *  \~english
    * @brief Listener for connection state changes<br/>
    * This class handles events that occur upon successful connection and connection failure.
    *
    *  \~
    * @ingroup Connection
    */
    public class ConnectionHandler {

        /**
        *  \~korean
        * 연결 성공 시 호출되는 이벤트<br/>
        * Called when the connection is successfully established
        *
        *  \~english
        * @brief 연결 성공 시 호출되는 이벤트<br/>
        * Called when the connection is successfully established
        */
        public Action OnConnected { get; set; }

        /**
        *  \~korean
        * @brief 재연결 시도 시작 이벤트<br/>
        *
        *  \~english
        * @brief Called when a reconnect attempt is about to start<br/>
        */
        public Action OnReconnectStarted { get; set; }

        /**
        *  \~korean
        * @brief 재연결 수행 후 호출되는 이벤트<br/>
        *
        *  \~english
        * @brief Called after re-connection is attempted<br/>
        */
        public Action<ResultAPI, List<String>, List<String>> OnReconnected { get; set; }

        /**
        *  \~korean
        * 연결 실패 시 호출되는 이벤트<br/>
        * Called when the connection fails
        *
        *  \~english
        * @brief 연결 실패 시 호출되는 이벤트<br/>
        * Called when the connection fails
        */
        public Action OnDisconnected { get; set; }

        public void Connect() { OnConnected?.Invoke(); }
        public void ReconnectStarted() { OnReconnectStarted?.Invoke(); }
        public void Reconnect(ResultAPI result, List<String> channelIds, List<String> failChannelIds) { OnReconnected?.Invoke(result, channelIds, failChannelIds); }
        public void Disconnect() { OnDisconnected?.Invoke(); }
    }

    /**
    *  \~korean
    * @brief 채널 관련 이벤트를 처리하는 리스너<br/>
    * 이 클래스는 채널에서 발생하는 다양한 이벤트를 처리합니다.
    *
    *  \~english
    * @brief Listener for handling channel-related events<br/>
    * This class handles various events occurring in a channel.
    *
    *  \~
    * @ingroup Channel
    */
    public class ChannelHandler {

        /**
        *  \~korean
        * 채널에 멤버가 입장할 때 호출되는 이벤트<br/>
        * Called when a member enters the channel
        *
        *  \~english
        * @brief 채널에 멤버가 입장할 때 호출되는 이벤트<br/>
        * Called when a member enters the channel
        */
        public Action<EnteredMember> OnEnteredMember { get; set; }

        /**
        *  \~korean
        * 채널에서 멤버가 퇴장할 때 호출되는 이벤트<br/>
        * Called when a member exits the channel
        *
        *  \~english
        * @brief 채널에서 멤버가 퇴장할 때 호출되는 이벤트<br/>
        * Called when a member exits the channel
        */
        public Action<ExitedMember> OnExitedMember { get; set; }

        /**
        *  \~korean
        * 채널 삭제 시 호출되는 이벤트<br/>
        * Called when a channel is deleted
        *
        *  \~english
        * @brief 채널 삭제 시 호출되는 이벤트<br/>
        * Called when a channel is deleted
        */
        public Action<DeletedChannel> OnDeletedChannel { get; set; }

        /**
        *  \~korean
        * 채널 공지 메시지 수신 시 호출되는 이벤트<br/>
        * Called when a channel notice message is received
        *
        *  \~english
        * @brief 채널 공지 메시지 수신 시 호출되는 이벤트<br/>
        * Called when a channel notice message is received
        */
        public Action<ChannelNoticeMessage> OnNoticeMessage { get; set; }

        /**
        *  \~korean
        * 채널 메시지 수신 시 호출되는 이벤트<br/>
        * Called when a channel message is received
        *
        *  \~english
        * @brief 채널 메시지 수신 시 호출되는 이벤트<br/>
        * Called when a channel message is received
        */
        public Action<ChannelMessage> OnChannelMessage { get; set; }

        /**
        *  \~korean
        * 리액션 추가 시 호출되는 이벤트<br/>
        * 
        *  \~english
        * Called when a reaction is added<br/>
        */
        public Action<Reaction> OnAddReaction { get; set; }

        /**
        *  \~korean
        * 리액션 제거 시 호출되는 이벤트<br/>
        * 
        *  \~english
        * Called when a reaction is removed<br/>
        */
        public Action<Reaction> OnRemoveReaction { get; set; }

        public void EnteredMember(EnteredMember member) { OnEnteredMember?.Invoke(member); }
        public void ExitedMember(ExitedMember member) { OnExitedMember?.Invoke(member); }
        public void DeletedChannel(DeletedChannel channel) { OnDeletedChannel?.Invoke(channel); }
        public void NoticeMessage(ChannelNoticeMessage message) { OnNoticeMessage?.Invoke(message); }
        public void ChannelMessage(ChannelMessage message) { OnChannelMessage?.Invoke(message); }
        public void AddReaction(Reaction reaction) { OnAddReaction?.Invoke(reaction); }
        public void RemoveReaction(Reaction reaction) { OnRemoveReaction?.Invoke(reaction); }
    }

    /**
    *  \~korean
    * @brief 1:1 메시지 관련 이벤트를 처리하는 리스너<br/>
    * 이 클래스는 1:1 메시지에서 발생하는 이벤트를 처리합니다.<br/>
    * @deprecated v25.4.0부터 종료되었습니다. 대신 UserHandler를 사용하세요.
    *
    *  \~english
    * @brief Listener for handling 1:1 message-related events<br/>
    * This class handles events occurring in direct messages.<br/>
    * @deprecated Deprecated since v25.4.0. Use UserHandler instead.
    *
    *  \~
    * @ingroup DirectMessage
    */
    [System.Obsolete("Deprecated since v25.4.0. Use UserHandler instead.")]
    public class DirectMessageHandler {

        /**
        *  \~korean
        * @brief1:1 메시지 수신 시 호출되는 이벤트<br/>
        *
        *  \~english
        * @brief Called when a direct message is received
        */
        public Action<DirectMessage> OnDirectMessage { get; set; }

        public void DirectMessage(DirectMessage message) { OnDirectMessage?.Invoke(message); }
    }

    /**
    *  \~korean
    * @brief 사용자 관련 메시지 이벤트를 처리하는 리스너<br/>
    *
    *  \~english
    * @brief Listener for handling user-related message events<br/>
    *
    *  \~
    * @ingroup User
    */
    public class UserHandler {

        /**
        *  \~korean
        * @brief1:1 메시지 수신 시 호출되는 이벤트<br/>
        *
        *  \~english
        * @brief Called when a direct message is received
        */
        public Action<DirectMessage> OnDirectMessage { get; set; }

        /**
        *  \~korean
        * @brief 공지 메시지 수신 시 호출되는 이벤트<br/>
        *
        *  \~english
        * @brief Called when a notice message is received
        */
        public Action<NoticeMessage> OnNoticeMessage { get; set; }

        public void DirectMessage(DirectMessage message) { OnDirectMessage?.Invoke(message); }

        public void NoticeMessage(NoticeMessage message) { OnNoticeMessage?.Invoke(message); }
    }

    /**
    *  \~korean
    * @brief 커스텀 데이터를 수신하는 리스너<br/>
    * 서버로부터 전달된 커스텀 문자열 데이터를 수신하여 처리하는 리스너입니다.
    *
    *  \~english
    * @brief Listener for receiving custom data<br/>
    * This listener receives custom string data sent from the server and handles it.
    *
    *  \~
    * @ingroup CustomData
    */
    public class CustomDataHandler {

        /**
        *  \~korean
        * @brief 커스텀 데이터 수신 시 호출되는 이벤트<br/>
        * 서버로부터 커스텀 데이터가 수신되었을 때 호출됩니다.
        *
        *  \~english
        * @brief Called when custom data is received<br/>
        * Invoked when custom data is received from the server.
        */
        public Action<String> OnCustomData { get; set; }

        public void CustomData(String data) { OnCustomData?.Invoke(data); }
    }

    public class ChannelSendMessageHandler {
        public hive.Chat.onChannelSendMessage listener;
        public ChannelSendMessageParams param;

        public ChannelSendMessageHandler(hive.Chat.onChannelSendMessage listener, ChannelSendMessageParams param) {
            this.listener = listener;
            this.param = param;
        }
    }

    public class DirectSendMessageHandler {
        public hive.Chat.onDirectSendMessage listener;
        public DirectSendMessageParams param;

        public DirectSendMessageHandler(hive.Chat.onDirectSendMessage listener, DirectSendMessageParams param) {
            this.listener = listener;
            this.param = param;
        }
    }
}


/** @} */



