import cqhttp as _cqhttp

# working as a replacement.
Error = _cqhttp.Error


class CQHttp(_cqhttp.CQHttp):
    """
    **CoolQ HTTP API Python SDK封装类**

    :作者: SuperMarioSF
    :参考: HTTP API v3.4
    :版本: v1.0

    本类封装了CoolQ HTTP API的Python SDK中对应HTTP API的所有API。
    封装时参考并引用了HTTP API所提供的文档。


    感谢 **richardchien** 为我们提供了如此简便酷Q应用开发方式。

    本文件使用 WTFPL 2.0 许可证发布。

    ------------

    本文件适用于JetBrains PyCharm开发环境。
    你可以在PyCharm中在任何使用到本类的封装方法的位置按下 **Ctrl+Q** 来快速查看文档的内容。

    本页帮助文档也会下方会介绍原Python SDK中已有的功能的用法。

    要查看HTTP API的完整在线文档,请访问:

    | https://richardchien.github.io/coolq-http-api/
    | http://richardchien.gitee.io/coolq-http-api/docs/

    ------------

    **使用本文件**

    你可以将本文件作为导入 cqhttp 包的替代来使用。
    但需要注意,本文件需要你的 Python 环境中能够导入原 cqhttp 包,因为本文件只是对原 cqhttp 包的封装。
    在用本文件在PyCharm IDE开发完毕之后,你可以直接把对本文件的引用恢复为对原 cqhttp 包的引用。

    将原先导入 cqhttp 包的写法:

    >>> from cqhttp import CQHttp, Error

    更换成:

    >>> from cqhttp_helper import CQHttp, Error

    即可完成对本文件的所有内容的引用,享受自动补全和即时文档吧!

    在本帮助页面中,`bot` 指的是已初始化的 CQHttp 对象。

    ------------

    **对象列表**

    | cqhttp_helper.CQHttp(api_root=None, access_token=None, secret=None): CQHttp 封装类,继承原 cqhttp 的 CQHttp 类,提供封装的方法列表和实时帮助信息。
    | cqhttp_helper.Error(status_code, retcode=None): CQHttp 异常类。直接引用 cqhttp 的 Error 类,用于兼容目的。

    ------------

    **cqhttp_helper.CQHttp 中封装的方法列表**

    | send_private_msg(self, *, user_id, message, auto_escape=False): 发送私聊消息
    | send_private_msg_async(self, *, user_id, message, auto_escape=False): 发送私聊消息 (异步版本)
    | send_group_msg(self, *, group_id, message, auto_escape=False): 发送群消息
    | send_group_msg_async(self, *, group_id, message, auto_escape=False): 发送群消息 (异步版本)
    | send_discuss_msg(self, *, discuss_id, message, auto_escape=False): 发送讨论组消息
    | send_discuss_msg_async(self, *, discuss_id, message, auto_escape=False): 发送讨论组消息 (异步版本)
    | send_msg(self, *, message_type, user_id=None, group_id=None, discuss_id=None, message, auto_escape=False): 发送消息
    | send_msg_async(self, *, message_type, user_id=None, group_id=None, discuss_id=None, message, auto_escape=False): 发送消息 (异步版本)
    | delete_msg(self, *, message_id): 撤回消息
    | send_like(self, *, user_id, times=1): 发送好友赞
    | set_group_kick(self, *, group_id, user_id, reject_add_request=False): 群组踢人
    | set_group_ban(self, *, group_id, user_id, duration=30 * 60): 群组单人禁言
    | set_group_anonymous_ban(self, *, group_id, flag, duration=30 * 60): 群组匿名用户禁言
    | set_group_whole_ban(self, *, group_id, enable=True): 群组全员禁言
    | set_group_admin(self, *, group_id, user_id, enable=True): 群组设置管理员
    | set_group_anonymous(self, *, group_id, enable=True): 群组匿名
    | set_group_card(self, *, group_id, user_id, card=None): 设置群名片(群备注)
    | set_group_leave(self, *, group_id, is_dismiss=False): 退出群组
    | set_group_special_title(self, *, group_id, user_id, special_title, duration=-1): 设置群组专属头衔
    | set_discuss_leave(self, *, discuss_id): 退出讨论组
    | set_friend_add_request(self, *, flag, approve=True, remark=None): 处理加好友请求
    | set_group_add_request(self, *, flag, type, approve=True, reason=None): 处理加群请求、群组成员邀请
    | get_login_info(self): 获取登录号信息
    | get_stranger_info(self, *, user_id, no_cache=False): 获取陌生人信息
    | get_group_list(self): 获取群列表
    | get_group_member_info(self, *, group_id, user_id, no_cache=False): 获取群成员信息
    | get_group_member_list(self, *, group_id): 获取群成员列表
    | get_cookies(self): 获取 Cookies
    | get_csrf_token(self): 获取 CSRF Token
    | get_record(self, *, file, out_format): 获取语音
    | get_status(self): 获取插件运行状态
    | get_version_info(self): 获取酷 Q 及 HTTP API 插件的版本信息
    | set_restart(self): 重启酷 Q,并以当前登录号自动登录(需勾选快速登录)
    | set_restart_plugin(self): 重启 HTTP API 插件
    | clean_data_dir(self, *, data_dir): 清理数据目录
    | clean_data_dir_async(self, *, data_dir): 清理数据目录 (异步版本)
    | _get_friend_list(self): 获取好友列表 (实验性功能)

    ------------

    **创建实例**

    首先创建 CQHttp 类的实例,传入 api_root,即为酷 Q HTTP API 插件的监听地址,如果你不需要调用 API,也可以不传入。Access token 和签名密钥也在这里传入,如果没有配置 access_token 或 secret 项,则不传。

    ------------

    **异常处理**

    每个 API 调用最后都会由 `requests` 库来发出请求,如果网络无法连接,它可能会抛出 `ConnectionError` 等异常,见 requests错误与异常_ 。而一旦请求成功,本 SDK 会判断 HTTP 响应状态码,只有当状态码为 200,且 status 字段为 ok 或 async 时,会返回 data 字段的内容,否则抛出 cqhttp.Error 异常,在这个异常中你可以通过 status_code 和 retcode 属性来获取 HTTP 状态码和插件的 retcode(如果状态码不为 200,则 retcode 为 None),具体响应状态码和 retcode 的含义,见 响应说明_ 。

    .. _requests错误与异常: http://cn.python-requests.org/zh_CN/latest/user/quickstart.html#id11
    .. _响应说明: https://richardchien.github.io/coolq-http-api/#/API?id=%E5%93%8D%E5%BA%94%E8%AF%B4%E6%98%8E

    ------------

    **消息发送**

    为了简化发送消息的操作,Python SDK 提供了 send(context, message) 函数,这里的第一个参数 context 也就是上报数据,传入之后函数会自己判断当前需要发送到哪里(哪个好友,或哪个群),无需手动再指定,其它参数仍然可以从 keyword argument 指定,例如 auto_escape=True。

    以 `send_` 开头(也就是消息发送相关)的接口都会包含一个 `message` 的参数。此参数接受普通的字符串(str),也接受一个特定格式的列表(list)。列表格式在原HTTP API文档中是表示为 `array` ,称为 JSON数组类型。在Python中,表示为一个列表(list)中包括的数个字典(dict)。

    以下是调用范例:

    .. code-block:: python

        # 以字符串形式发送的普通消息。
        bot.send_private_message(user_id=1234567,
                    message="这是一条普通消息。\\n可以用这种方式换行。"

        # 以列表(list)形式发送的多段消息组合。
        bot.send_private_message(user_id=1234567,
                message=[
                                {
                                    "type": "text",
                                    "data": {"text": "这是第一段"}
                                },
                                {
                                    "type": "face",
                                    "data": {"id": "111"}
                                },
                                {
                                    "type": "text",
                                    "data": {"text": "这是表情之后的一段。"}
                                }
                        ])

    关于多段消息的每个单段的具体格式,请参见 HTTP API 文档中的 **消息格式** 的 **消息段(广义 CQ 码)** 一节。

    ------------

    **事件处理**

    `on_message`、`on_event`、`on_request` 三个装饰器分别对应三个上报类型(`post_type`),括号中指出要处理的消息类型(`message_type`)、事件名(`event`)、请求类型(`request_type`),一次可指定多个,如果留空,则会处理所有这个上报类型的上报。

    以下为范例:

    .. code-block:: python

        # 监听消息输入
        @bot.on_message()
        def handle_msg(context):
          bot.send(context, '你好呀,下面一条是你刚刚发的:')
          return {'reply': context['message'], 'at_sender': False}

        # 监听群组成员增加事件
        @bot.on_event('group_increase')
        def handle_group_increase(context):
           bot.send(context, message='欢迎新人~', is_raw=True)  # 发送欢迎新人

        # 监听加群和加好友请求
        @bot.on_request('group', 'friend')
        def handle_request(context):
           return {'approve': True}  # 同意所有加群、加好友请求


        bot.run(host='127.0.0.1', port=8080)

    上面三个装饰器装饰的函数,统一接受一个参数,即为上报的数据,具体数据内容见  事件上报_ ;返回值可以是一个字典,会被自动作为 JSON 响应返回给 HTTP API 插件,具体见 上报请求的响应数据格式_ 。


    .. _事件上报: https://richardchien.github.io/coolq-http-api/#/Post
    .. _上报请求的响应数据格式: https://richardchien.github.io/coolq-http-api/#/Post?id=%E4%B8%8A%E6%8A%A5%E8%AF%B7%E6%B1%82%E7%9A%84%E5%93%8D%E5%BA%94%E6%95%B0%E6%8D%AE%E6%A0%BC%E5%BC%8F

    ------------

    **运行实例**

    使用装饰器定义好处理函数之后,调用 `bot.run()` 即可运行。你需要传入 `host` 和 `port` 参数,来指定服务端需要运行在哪个地址,**然后在 HTTP API 插件的配置文件中,在 `post_url` 项中配置此地址(http://host:port/)**。

    **务必注意:** 如果不在插件配置文件中指定 `post_url` 为运行实例时指定的地址,Python SDK 将无法收到任何消息和事件。



    """
    def __init__(self, api_root=None, access_token=None, secret=None):
        """
        创建 CoolQ HTTP API 对象

        ------------

        :param str | None api_root: 酷 Q HTTP API 插件的监听地址的 URL ,与 HTTP API 的配置文件设定和实际使用环境相关。如果你不需要调用 API,也可以不传入。
        :param str | None access_token: 插件配置文件中所指定的 `access_token` 。如果未设定可不传此参数。
        :param str | None secret: 插件配置文件中所指定的 `secret` 。如果未设定可不传此参数。
        """
        super().__init__(api_root=api_root, access_token=access_token, secret=secret)

    def send_private_msg(self, *, user_id, message, auto_escape=False):
        '''
        发送私聊消息

        ------------

        :param int user_id: 对方 QQ 号
        :param str | list[ dict[ str, unknown ] ] message: 要发送的内容
        :param bool auto_escape: 消息内容是否作为纯文本发送(即不解析 CQ 码),`message` 数据类型为 `list` 时无效
        :return: {"message_id": int 消息ID}
        :rtype: dict[string, int]
        '''
        return super().__getattr__('send_private_msg') \
            (user_id=user_id, message=message, auto_escape=auto_escape)

    def send_private_msg_async(self, *, user_id, message, auto_escape=False):
        """
        发送私聊消息 (异步版本)

        ------------

        :param int user_id: 对方 QQ 号
        :param str | list[ dict[ str, unknown ] ] message: 要发送的内容
        :param bool auto_escape: 消息内容是否作为纯文本发送(即不解析 CQ 码),`message` 数据类型为 `list` 时无效
        :return: None
        :rtype: None
        """
        return super().__getattr__('send_private_msg_async') \
            (user_id=user_id, message=message, auto_escape=auto_escape)

    def send_group_msg(self, *, group_id, message, auto_escape=False):
        """
        发送群消息

        ------------

        :param int group_id: 群号
        :param str | list[ dict[ str, unknown ] ] message: 要发送的内容
        :param bool auto_escape: 消息内容是否作为纯文本发送(即不解析 CQ 码),`message` 数据类型为 `list` 时无效
        :return: {"message_id": int 消息ID}
        :rtype: dict[string, int]
        """
        return super().__getattr__('send_group_msg') \
            (group_id=group_id, message=message, auto_escape=auto_escape)

    def send_group_msg_async(self, *, group_id, message, auto_escape=False):
        """
        发送群消息 (异步版本)

        ------------

        :param int group_id: 群号
        :param str | list[ dict[ str, unknown ] ] message: 要发送的内容
        :param bool auto_escape: 消息内容是否作为纯文本发送(即不解析 CQ 码),`message` 数据类型为 `list` 时无效
        :return: None
        :rtype: None
        """
        return super().__getattr__('send_group_msg_async') \
            (group_id=group_id, message=message, auto_escape=auto_escape)

    def send_discuss_msg(self, *, discuss_id, message, auto_escape=False):
        """
        发送讨论组消息

        ------------

        :param int discuss_id: 讨论组 ID(正常情况下看不到,需要从讨论组消息上报的数据中获得)
        :param str | list[ dict[ str, unknown ] ] message: 要发送的内容
        :param bool auto_escape: 消息内容是否作为纯文本发送(即不解析 CQ 码),`message` 数据类型为 `list` 时无效
        :return: {"message_id": int 消息ID}
        :rtype: dict[string, int]
        """
        return super().__getattr__('send_discuss_msg') \
            (discuss_id=discuss_id, message=message, auto_escape=auto_escape)

    def send_discuss_msg_async(self, *, discuss_id, message, auto_escape=False):
        """
        发送讨论组消息 (异步版本)

        ------------

        :param int discuss_id: 讨论组 ID(正常情况下看不到,需要从讨论组消息上报的数据中获得)
        :param str | list[ dict[ str, unknown ] ] message: 要发送的内容
        :param bool auto_escape: 消息内容是否作为纯文本发送(即不解析 CQ 码),`message` 数据类型为 `list` 时无效
        :return: None
        :rtype: None
        """
        return super().__getattr__('send_discuss_msg_async') \
            (discuss_id=discuss_id, message=message, auto_escape=auto_escape)

    def send_msg(self, *, message_type, user_id=None, group_id=None, discuss_id=None, message, auto_escape=False):
        """
        发送消息

        ------------

        :param str message_type: 消息类型,支持 `private`、`group`、`discuss`,分别对应私聊、群组、讨论组
        :param int user_id: 对方 QQ 号(消息类型为 `private` 时需要)
        :param int group_id: 群号(消息类型为 `group` 时需要)
        :param int discuss_id: 讨论组 ID(需要从上报消息中获取,消息类型为 `discuss` 时需要)
        :param str | list[ dict[ str, unknown ] ] message: 要发送的内容
        :param bool auto_escape: 消息内容是否作为纯文本发送(即不解析 CQ 码),`message` 数据类型为 `list` 时无效
        :return: {"message_id": int 消息ID}
        :rtype: dict[string, int]
        """
        return super().__getattr__('send_msg') \
            (message_type=message_type, user_id=user_id, group_id=group_id,
             discuss_id=discuss_id, message=message, auto_escape=auto_escape)

    def send_msg_async(self, *, message_type, user_id=None, group_id=None, discuss_id=None, message, auto_escape=False):
        """
        发送消息 (异步版本)

        ------------

        :param str message_type: 消息类型,支持 `private`、`group`、`discuss`,分别对应私聊、群组、讨论组
        :param int user_id: 对方 QQ 号(消息类型为 `private` 时需要)
        :param int group_id: 群号(消息类型为 `group` 时需要)
        :param int discuss_id: 讨论组 ID(需要从上报消息中获取,消息类型为 `discuss` 时需要)
        :param str | list[ dict[ str, unknown ] ] message: 要发送的内容
        :param bool auto_escape: 消息内容是否作为纯文本发送(即不解析 CQ 码),`message` 数据类型为 `list` 时无效
        :return: None
        :rtype: None
        """
        return super().__getattr__('send_msg_async') \
            (message_type=message_type, user_id=user_id, group_id=group_id,
             discuss_id=discuss_id, message=message, auto_escape=auto_escape)

    def delete_msg(self, *, message_id):
        """
        撤回消息

        ------------

        :param int message_id: 消息 ID
        :return: None
        :rtype: None
        """
        return super().__getattr__('delete_msg') \
            (message_id=message_id)

    def send_like(self, *, user_id, times=1):
        """
        发送好友赞

        ------------

        :param int user_id: 对方 QQ 号
        :param int times: 赞的次数,每个好友每天最多 10 次
        :return: None
        :rtype: None
        """
        return super().__getattr__('send_like') \
            (user_id=user_id, times=times)

    def set_group_kick(self, *, group_id, user_id, reject_add_request=False):
        """
        群组踢人

        ------------

        :param int group_id: 群号
        :param int user_id: 要踢的 QQ 号
        :param bool reject_add_request: 拒绝此人的加群请求
        :return: None
        :rtype: None
        """
        return super().__getattr__('set_group_kick') \
            (group_id=group_id, user_id=user_id, reject_add_request=reject_add_request)

    def set_group_ban(self, *, group_id, user_id, duration=30 * 60):
        """
        群组单人禁言

        ------------

        :param int group_id: 群号
        :param int user_id: 要禁言的 QQ 号
        :param int duration: 禁言时长,单位秒,0 表示取消禁言
        :return: None
        :rtype: None
        """
        return super().__getattr__('set_group_ban') \
            (group_id=group_id, user_id=user_id, duration=duration)

    def set_group_anonymous_ban(self, *, group_id, flag, duration=30 * 60):
        """
        群组匿名用户禁言

        ------------

        :param int group_id: 群号
        :param str flag: 要禁言的匿名用户的 flag(需从群消息上报的数据中获得)
        :param int duration: 禁言时长,单位秒,**无法取消匿名用户禁言**
        :return: None
        :rtype: None
        """
        return super().__getattr__('set_group_anonymous_ban') \
            (group_id=group_id, flag=flag, duration=duration)

    def set_group_whole_ban(self, *, group_id, enable=True):
        """
        群组全员禁言

        ------------

        :param int group_id: 群号
        :param bool enable: 是否禁言
        :return: None
        :rtype: None
        """
        return super().__getattr__('set_group_whole_ban') \
            (group_id=group_id, enable=enable)

    def set_group_admin(self, *, group_id, user_id, enable=True):
        """
        群组设置管理员

        ------------

        :param int group_id: 群号
        :param user_id: 要设置管理员的 QQ 号
        :param enable: True 为设置,False 为取消
        :return: None
        :rtype: None
        """
        return super().__getattr__('set_group_admin') \
            (group_id=group_id, user_id=user_id, enable=enable)

    def set_group_anonymous(self, *, group_id, enable=True):
        """
        群组匿名

        ------------

        :param int group_id: 群号
        :param bool enable: 是否允许匿名聊天
        :return: None
        :rtype: None
        """
        return super().__getattr__('set_group_anonymous') \
            (group_id=group_id, enable=enable)

    def set_group_card(self, *, group_id, user_id, card=None):
        """
        设置群名片(群备注)

        ------------

        :param int group_id: 群号
        :param int user_id: 要设置的 QQ 号
        :param str | None card: 群名片内容,不填或空字符串表示删除群名片
        :return: None
        :rtype: None
        """
        return super().__getattr__('set_group_card') \
            (group_id=group_id, user_id=user_id, card=card)

    def set_group_leave(self, *, group_id, is_dismiss=False):
        """
        退出群组

        ------------

        :param int group_id: 群号
        :param bool is_dismiss: 是否解散,如果登录号是群主,则仅在此项为 true 时能够解散
        :return: None
        :rtype: None
        """
        return super().__getattr__('set_group_leave') \
            (group_id=group_id, is_dismiss=is_dismiss)

    def set_group_special_title(self, *, group_id, user_id, special_title, duration=-1):
        """
        设置群组专属头衔

        ------------

        :param int group_id: 群号
        :param int user_id: 要设置的 QQ 号
        :param str special_title: 专属头衔,不填或空字符串表示删除专属头衔,只能保留前6个英文与汉字,Emoji 根据字符实际字符长度占用只能放最多3个甚至更少,超出长度部分会被截断
        :param int duration: 专属头衔有效期,单位秒,-1 表示永久,不过此项似乎没有效果,可能是只有某些特殊的时间长度有效,有待测试
        :return: None
        :rtype: None
        """
        return super().__getattr__('set_group_special_title') \
            (group_id=group_id, user_id=user_id, special_title=special_title, duration=duration)

    def set_discuss_leave(self, *, discuss_id):
        """
        退出讨论组

        ------------

        :param int discuss_id: 讨论组 ID(正常情况下看不到,需要从讨论组消息上报的数据中获得)
        :return: None
        :rtype: None
        """
        return super().__getattr__('set_discuss_leave') \
            (discuss_id=discuss_id)

    def set_friend_add_request(self, *, flag, approve=True, remark=None):
        """
        处理加好友请求

        ------------

        :param str flag: 加好友请求的 flag(需从上报的数据中获得)
        :param bool approve: 是否同意请求
        :param str remark: 添加后的好友备注(仅在同意时有效)
        :return: None
        :rtype: None
        """
        return super().__getattr__('set_friend_add_request') \
            (flag=flag, approve=approve, remark=remark)

    def set_group_add_request(self, *, flag, type, approve=True, reason=None):
        """
        处理加群请求、群组成员邀请

        ------------

        :param str flag: 加群请求的 flag(需从上报的数据中获得)
        :param str type: `add` 或 `invite`,请求类型(需要和上报消息中的 `sub_type` 字段相符)
        :param bool approve: 是否同意请求/邀请
        :param str reason: 拒绝理由(仅在拒绝时有效)
        :return: None
        :rtype: None
        """
        return super().__getattr__('set_group_add_request') \
            (flag=flag, type=type, approve=approve, reason=reason)

    def get_login_info(self):
        """
        获取登录号信息

        ------------

        :return: { "user_id": (QQ 号: int), "nickname": (QQ 昵称: str) }
        :rtype: dict[ str, int | str ]

        ------------

        =========  =========  =========
        响应数据
        -------------------------------
        数据类型   字段名      说明
        =========  =========  =========
        int        user_id    QQ 号
        str        nickname   QQ 昵称
        =========  =========  =========
        """
        return super().__getattr__('get_login_info') \
            ()

    def get_stranger_info(self, *, user_id, no_cache=False):
        """
        获取陌生人信息

        ------------

        :param int user_id: QQ 号(不可以是登录号)
        :param bool no_cache: 是否不使用缓存(使用缓存可能更新不及时,但响应更快)
        :return: { "user_id": (QQ 号: int), "nickname": (昵称: str), "sex": (性别: str in ['male', 'female', 'unknown']), "age": (年龄: int) }
        :rtype: dict[ str, int | str ]

        ------------

        ========  =========  ======================================
        响应数据
        -----------------------------------------------------------
        数据类型  字段名     说明
        ========  =========  ======================================
        int       user_id    QQ 号
        str       nickname   昵称
        str       sex        性别,`male` 或 `female` 或 `unknown`
        int       age        年龄
        ========  =========  ======================================

        """
        return super().__getattr__('get_stranger_info') \
            (user_id=user_id, no_cache=no_cache)

    def get_group_list(self):
        """
        获取群列表

        ------------

        :return: [{ "group_id": (群号: int), "group_name": (群名称: str) }, ...]
        :rtype: list[ dict[ str, int | str ] ]

        ------------

        ========  ===========  =========
        响应数据
        --------------------------------
        数据类型  字段名       说明
        ========  ===========  =========
        int       group_id     群号
        str       group_name   群名称
        ========  ===========  =========

        """
        return super().__getattr__('get_group_list') \
            ()

    def get_group_member_info(self, *, group_id, user_id, no_cache=False):
        """
        获取群成员信息

        ------------

        :param int group_id: 群号
        :param int user_id: QQ 号(不可以是登录号)
        :param bool no_cache: 是否不使用缓存(使用缓存可能更新不及时,但响应更快)
        :return: { "group_id": (群号: int), "user_id": (QQ 号: int), "nickname": (昵称: str), "card": (群名片/备注: str), "sex": (性别: str in ['male', 'female', 'unknown']), "age": (年龄: int), "area": (地区: str), "join_time": (加群时间戳: int), "last_sent_time": (最后发言时间戳: int), "level": (成员等级: str), "role": (角色: str in ['owner', 'admin', 'member']), "unfriendly": (是否不良记录成员: bool), "title": (专属头衔: str), "title_expire_time": (专属头衔过期时间戳: int), "card_changeable": (是否允许修改群名片: bool) }
        :rtype: dict[ str, int | str | bool ]

        ------------

        ========  ===================  ======================================
            响应数据
        ---------------------------------------------------------------------
        数据类型  字段名               说明
        ========  ===================  ======================================
        int       group_id             群号
        int       user_id              QQ 号
        str       nickname             昵称
        str       card                 群名片/备注
        str       sex                  性别,`male` 或 `female` 或 `unknown`
        int       age                  年龄
        str       area                 地区
        int       join_time            加群时间戳
        int       last_sent_time       最后发言时间戳
        str       level                成员等级
        str       role                 角色,`owner` 或 `admin` 或 `member`
        bool      unfriendly           是否不良记录成员
        str       title                专属头衔
        int       title_expire_time    专属头衔过期时间戳
        bool      card_changeable      是否允许修改群名片
        ========  ===================  ======================================
        """
        return super().__getattr__('get_group_member_info') \
            (group_id=group_id, user_id=user_id, no_cache=no_cache)

    def get_group_member_list(self, *, group_id):
        """
        获取群成员列表

        ------------

        :param int group_id: 群号
        :return: [{ "group_id": (群号: int), "user_id": (QQ 号: int), "nickname": (昵称: str), "card": (群名片/备注: str), "sex": (性别: str in ['male', 'female', 'unknown']), "age": (年龄: int), "area": (地区: str), "join_time": (加群时间戳: int), "last_sent_time": (最后发言时间戳: int), "level": (成员等级: str), "role": (角色: str in ['owner', 'admin', 'member']), "unfriendly": (是否不良记录成员: bool), "title": (专属头衔: str), "title_expire_time": (专属头衔过期时间戳: int), "card_changeable": (是否允许修改群名片: bool) }, ...]
        :rtype: list[ dict[ str, int | str | bool ] ]

        ------------

        响应数据以 **列表** 包装的字典的形式提供。`( List[ Dict[ ...] ] )`

        ========  ===================  ======================================
            响应数据
        ---------------------------------------------------------------------
        数据类型  字段名               说明
        ========  ===================  ======================================
        int       group_id             群号
        int       user_id              QQ 号
        str       nickname             昵称
        str       card                 群名片/备注
        str       sex                  性别,`male` 或 `female` 或 `unknown`
        int       age                  年龄
        str       area                 地区
        int       join_time            加群时间戳
        int       last_sent_time       最后发言时间戳
        str       level                成员等级
        str       role                 角色,`owner` 或 `admin` 或 `member`
        bool      unfriendly           是否不良记录成员
        str       title                专属头衔
        int       title_expire_time    专属头衔过期时间戳
        bool      card_changeable      是否允许修改群名片
        ========  ===================  ======================================

        **备注:** 响应内容为包含字典的列表 *( List[ Dict[] ] )* ,每个元素的内容和 `get_group_member_info` 接口相同,但对于同一个群组的同一个成员,获取列表时和获取单独的成员信息时,某些字段可能有所不同,例如 `area`、`title` 等字段在获取列表时无法获得,具体应以单独的成员信息为准。

        """
        return super().__getattr__('get_group_member_list') \
            (group_id=group_id)

    def get_cookies(self):
        """
        获取 Cookies

        ------------

        :return: { "cookies": (Cookies: str)}
        :rtype: dict[ str, str ]

        ------------

        ========  ===========  =========
        响应数据
        --------------------------------
        数据类型  字段名       说明
        ========  ===========  =========
        str       cookies      Cookies
        ========  ===========  =========

        """
        return super().__getattr__('get_cookies') \
            ()

    def get_csrf_token(self):
        """
        获取 CSRF Token

        ------------

        :return: { "token": (CSRF Token: int)}
        :rtype: dict[ str, int ]

        ------------

        ========  ===========  ==========
        响应数据
        ---------------------------------
        数据类型  字段名       说明
        ========  ===========  ==========
        int       token        CSRF Token
        ========  ===========  ==========

        """
        return super().__getattr__('get_csrf_token') \
            ()

    def get_record(self, *, file, out_format):
        """
        获取语音

        ------------

        :param str file: 收到的语音文件名,如 `0B38145AA44505000B38145AA4450500.silk`
        :param str out_format: 要转换到的格式,目前支持 `mp3`、`amr`、`wma`、`m4a`、`spx`、`ogg`、`wav`、`flac`
        :return: { "file": (转换后的语音文件名: str)}
        :rtype: dict[ str, str ]


        ------------

        其实并不是真的获取语音,而是转换语音到指定的格式,然后返回语音文件名(`data/record` 目录下)。

        ========  ===========  =============================================================
        响应数据
        ------------------------------------------------------------------------------------
        数据类型   字段名       说明
        ========  ===========  =============================================================
        str       file          转换后的语音文件名,如 `0B38145AA44505000B38145AA4450500.mp3`
        ========  ===========  =============================================================

        """
        return super().__getattr__('get_record') \
            (file=file, out_format=out_format)

    def get_status(self):
        """
        获取插件运行状态

        ------------

        :return: { "good": (正常运行: bool), "app_initialized": (插件已初始化: bool), "app_enabled": (插件已启用: bool), "online": (当前QQ在线: bool), "http_service_good": (HTTP服务正常运行: bool), "ws_service_good": (WebSocket服务正常运行: bool), "ws_reverse_service_good": (反向WebSocket服务正常运行: bool) }
        :rtype: dict[ str, bool ]

        ------------

        ========  ========================  ====================================
        响应数据
        ------------------------------------------------------------------------
        数据类型  字段名                    说明
        ========  ========================  ====================================
        bool      good                      插件状态符合预期,意味着插件已初始化,需要启动的服务都在正常运行,且 QQ 在线
        bool      app_initialized           插件已初始化
        bool      app_enabled               插件已启用
        bool      online                    当前 QQ 在线
        bool      http_service_good         `use_http` 配置项为 `yes` 时有此字段,表示 HTTP 服务正常运行
        bool      ws_service_good           `use_ws` 配置项为 `yes` 时有此字段,表示 WebSocket 服务正常运行
        bool      ws_reverse_service_good   `use_ws_reverse` 配置项为 `yes` 时有此字段,表示反向 WebSocket 服务正常运行
        ========  ========================  ====================================
        """
        return super().__getattr__('get_status') \
            ()

    def get_version_info(self):
        """
        获取酷 Q 及 HTTP API 插件的版本信息

        ------------

        :return: { "coolq_directory": (酷Q根目录路径: str), "coolq_edition": (酷Q版本: str in ['air', 'pro']), "plugin_version": (API插件版本: str), "plugin_build_number": (API插件build号: int), "plugin_build_configuration": (API插件编译配置: str in ['debug', 'release']) }
        :rtype: dict[ str, int | str ]


        ------------

        ========  ==========================  ===============================
        响应数据
        ---------------------------------------------------------------------
        数据类型  字段名                      说明
        ========  ==========================  ===============================
        str       coolq_directory             酷 Q 根目录路径
        str       coolq_edition               酷 Q 版本,`air` 或 `pro`
        str       plugin_version              HTTP API 插件版本,例如 2.1.3
        int       plugin_build_number         HTTP API 插件 build 号
        str       plugin_build_configuration  HTTP API 插件编译配置,`debug` 或 `release`
        ========  ==========================  ===============================
        """
        return super().__getattr__('get_version_info') \
            ()

    def set_restart(self):
        """
        重启酷 Q,并以当前登录号自动登录(需勾选快速登录)

        ------------

        :return: None
        :rtype: None
        """
        return super().__getattr__('set_restart') \
            ()

    def set_restart_plugin(self):
        """
        重启 HTTP API 插件

        ------------

        :return: None
        :rtype: None

        ------------

        由于重启插件同时需要重启 API 服务,这意味着当前的 API 请求会被中断,因此这个接口会延迟 2 秒重启插件,接口返回的 status 是 async。

        **在Python SDK中返回 None 。**
        """
        return super().__getattr__('set_restart_plugin') \
            ()

    def clean_data_dir(self, *, data_dir):
        """
        清理数据目录

        ------------

        :param str data_dir: 收到清理的目录名,支持 `image`、`record`、`show`、`bface`
        :return: None
        :rtype: None

        ------------

        用于清理积攒了太多旧文件的数据目录,如 `image`。

        HTTP API v3.3.4 新增
        """
        return super().__getattr__('clean_data_dir') \
            (data_dir=data_dir)

    def clean_data_dir_async(self, *, data_dir):
        """
        清理数据目录 (异步版本)

        ------------

        :param str data_dir: 收到清理的目录名,支持 `image`、`record`、`show`、`bface`
        :return: None
        :rtype: None

        ------------

        用于清理积攒了太多旧文件的数据目录,如 `image`。

        HTTP API v3.3.4 新增
        """
        return super().__getattr__('clean_data_dir_async') \
            (data_dir=data_dir)

    def _get_friend_list(self):
        """
        获取好友列表 (实验性功能)

        ------------

        :return: [{ "friend_group_id": (好友分组 ID: int), "friend_group_name": (好友分组名称: str), "friends": (分组中的好友: [{ "nickname": (好友昵称: str), "remark": (好友备注: str), "user_id": (好友 QQ 号: int) }, ...]) }, ...]
        :rtype: list[ dict[ str, int | str | list[ dict[ str, int | str ] ] ] ]

        ------------

        响应数据以 **列表** 包装的字典的形式提供。`( List[ Dict[ ...] ] )`

        ========  ==================  ===============================
        响应数据
        -------------------------------------------------------------
        数据类型  字段名                      说明
        ========  ==================  ===============================
        int       friend_group_id     好友分组 ID
        str       friend_group_name   好友分组名称
        list      friends             分组中的好友
        ========  ==================  ===============================

        其中,好友信息结构以 **字典** 的形式存储在响应数据中的分组中的好友 `friends` 的 **列表** 中。`( List[ Dict[ ...] ] )`

        ========  ==================  ===============================
        好友信息结构
        -------------------------------------------------------------
        数据类型  字段名                      说明
        ========  ==================  ===============================
        str       nickname            好友昵称
        str       remark              好友备注
        int       user_id             好友 QQ 号
        ========  ==================  ===============================

        """
        return super().__getattr__('_get_friend_list') \
            ()

    def send(self, context, message, **kwargs):
        """
        便捷回复。会根据传入的context自动判断回复对象
        ------------
        :param dict context: 事件收到的content
        :return: None
        :rtype: None
        ------------
        """
        context = context.copy()
        context['message'] = message
        context.update(kwargs)
        if 'message_type' not in context:
            if 'group_id' in context:
                context['message_type'] = 'group'
            elif 'discuss_id' in context:
                context['message_type'] = 'discuss'
            elif 'user_id' in context:
                context['message_type'] = 'private'
        return super().__getattr__('send_msg')(**context)