/*
 * Copyright 2020 Mamoe Technologies and contributors.
 *
 * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
 * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
 *
 * https://github.com/mamoe/mirai/blob/master/LICENSE
 */

@file:Suppress("EXPERIMENTAL_UNSIGNED_LITERALS", "EXPERIMENTAL_API_USAGE")

package demo.subscribe

import net.mamoe.mirai.Bot
import net.mamoe.mirai.BotAccount
import net.mamoe.mirai.alsoLogin
import net.mamoe.mirai.contact.QQ
import net.mamoe.mirai.contact.sendMessage
import net.mamoe.mirai.event.*
import net.mamoe.mirai.message.FriendMessage
import net.mamoe.mirai.message.GroupMessage
import net.mamoe.mirai.message.data.Image
import net.mamoe.mirai.message.data.PlainText
import net.mamoe.mirai.message.data.firstOrNull
import net.mamoe.mirai.message.sendAsImageTo
import net.mamoe.mirai.qqandroid.Bot
import net.mamoe.mirai.qqandroid.QQAndroid
import java.io.File

private fun readTestAccount(): BotAccount? {
    val file = File("testAccount.txt")
    if (!file.exists() || !file.canRead()) {
        return null
    }

    println("Reading account from testAccount.text")
    val lines = file.readLines()
    return try {
        BotAccount(lines[0].toLong(), lines[1])
    } catch (e: IndexOutOfBoundsException) {
        null
    }
}

@Suppress("UNUSED_VARIABLE")
suspend fun main() {
    val bot = QQAndroid.Bot( // JVM 下也可以不写 `TIMPC.` 引用顶层函数
        1994701121,
        "123456"
    ) {
        // 覆盖默认的配置
        randomDeviceName = false
    }.alsoLogin()

    bot.messageDSL()
    directlySubscribe(bot)

    bot.network.awaitDisconnection()//等到直到断开连接
}

/**
 * 使用 dsl 监听消息事件
 *
 * @see subscribeFriendMessages
 * @see subscribeMessages
 * @see subscribeGroupMessages
 *
 * @see MessageSubscribersBuilder
 */
fun Bot.messageDSL() {
    // 监听这个 bot 的来自所有群和好友的消息
    this.subscribeMessages {
        // 当接收到消息 == "你好" 时就回复 "你好!"
        "你好" reply "你好!"

        // 当消息 == "查看 subject" 时, 执行 lambda
        case("查看 subject") {
            if (subject is QQ) {
                reply("消息主体为 QQ, 你在发私聊消息")
            } else {
                reply("消息主体为 Group, 你在群里发消息")
            }

            // 在回复的时候, 一般使用 subject 来作为回复对象.
            // 因为当群消息时, subject 为这个群.
            // 当好友消息时, subject 为这个好友.
            // 所有在 MessagePacket(也就是此时的 this 指代的对象) 中实现的扩展方法, 如刚刚的 "reply", 都是以 subject 作为目标
        }


        // 当消息里面包含这个类型的消息时
        has<Image> {
            // this: MessagePacket
            // message: MessageChain
            // sender: QQ
            // it: String (MessageChain.toString)


            message[Image].download()
            if (this is GroupMessage) {
                //如果是群消息
                // group: Group
                this.group.sendMessage("你在一个群里")
                // 等同于 reply("你在一个群里")
            }

            reply("图片, ID= ${message[Image]}")//获取第一个 Image 类型的消息
            reply(message)
        }

        "hello.*world".toRegex() matchingReply {
            "Hello!"
        }

        "123" containsReply "你的消息里面包含 123"


        // 当收到 "我的qq" 就执行 lambda 并回复 lambda 的返回值 String
        "我的qq" reply { sender.id }


        // 如果是这个 QQ 号发送的消息(可以是好友消息也可以是群消息)
        sentBy(123456789) {
        }


        // 当消息前缀为 "我是" 时
        startsWith("我是", removePrefix = true) {
            // it: 删除了消息前缀 "我是" 后的消息
            // 如一条消息为 "我是张三", 则此时的 it 为 "张三".

            reply("你是$it")
        }


        // 当消息中包含 "复读" 时
        val listener = (contains("复读1") or contains("复读2")) {
            reply(message)
        }

        listener.complete() // 停止监听

        // 自定义的 filter, filter 中 it 为转为 String 的消息.
        // 也可以用任何能在处理时使用的变量, 如 subject, sender, message
        content({ it.length == 3 }) {
            reply("你发送了长度为 3 的消息")
        }


        case("上传好友图片") {
            val filename = it.substringAfter("上传好友图片")
            File("C:\\Users\\Him18\\Desktop\\$filename").sendAsImageTo(subject)
        }

        case("上传群图片") {
            val filename = it.substringAfter("上传好友图片")
            File("C:\\Users\\Him18\\Desktop\\$filename").sendAsImageTo(subject)
        }
    }

    subscribeMessages {
        case("你好") {
            // this: MessagePacket
            // message: MessageChain
            // sender: QQ
            // it: String (来自 MessageChain.toString)
            // group: Group (如果是群消息)
            reply("你好")
        }
    }

    subscribeFriendMessages {
        contains("A") {
            // this: FriendMessage
            // message: MessageChain
            // sender: QQ
            // it: String (来自 MessageChain.toString)
            reply("B")
        }
    }

    subscribeGroupMessages {
        // this: FriendMessage
        // message: MessageChain
        // sender: QQ
        // it: String (来自 MessageChain.toString)
        // group: Group
    }
}

/**
 * 监听单个事件
 */
@Suppress("UNUSED_VARIABLE")
suspend fun directlySubscribe(bot: Bot) {
    // 在当前协程作用域 (CoroutineScope) 下创建一个子 Job, 监听一个事件.
    //
    // 手动处理消息
    // 使用 Bot 的扩展方法监听, 将在处理事件时得到一个 this: Bot.
    // 这样可以调用 Bot 内的一些扩展方法如 UInt.qq():QQ
    //
    // 这个函数返回 Listener, Listener 是一个 CompletableJob. 如果不手动 close 它, 它会一直阻止当前 CoroutineScope 结束.
    // 例如:
    // ```kotlin
    // runBlocking {// this: CoroutineScope
    //     bot.subscribeAlways<FriendMessage> {
    //     }
    // }
    // ```
    // 则这个 `runBlocking` 永远不会结束, 因为 `subscribeAlways` 在 `runBlocking` 的 `CoroutineScope` 下创建了一个 Job.
    // 正确的用法为:
    bot.subscribeAlways<FriendMessage> {
        // this: FriendMessageEvent
        // event: FriendMessageEvent

        // 获取第一个纯文本消息, 获取不到会抛出 NoSuchElementException
        // val firstText = message.first<PlainText>()

        val firstText = message.firstOrNull<PlainText>()

        // 获取第一个图片
        val firstImage = message.firstOrNull<Image>()

        when {
            message eq "你好" -> reply("你好!")

            "复读" in message -> sender.sendMessage(message)

            "发群消息" in message -> {
                bot.getGroup(580266363).sendMessage(message.toString().substringAfter("发群消息"))
            }
        }
    }
}