package com.kym.service.mq;

import cn.hutool.core.util.CharsetUtil;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.TypeReference;
import com.aliyun.mns.client.CloudAccount;
import com.aliyun.mns.client.CloudQueue;
import com.aliyun.mns.client.MNSClient;
import com.aliyun.mns.model.Message;
import com.kym.service.awoara.factory.AwoaraEventHandlerFactory;
import com.kym.service.awoara.entity.event.Event;
import com.kym.service.awoara.entity.event.MessageBody;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.text.StringEscapeUtils;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import java.util.Base64;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * MNS消息处理
 *
 * @author skyline
 */
@Component
@Slf4j
public class MnsHandler {

    /**
     * 线程池
     */
    private final static ExecutorService executorService = new ThreadPoolExecutor(
            2, 4, 60, TimeUnit.SECONDS,
            new LinkedBlockingQueue<>(10000));

    /**
     * 是否做 base64 编码
     */
    private static final Boolean IS_BASE64 = false;
    /**
     * BASE64解码器
     */
    private static Base64.Decoder decoder = Base64.getDecoder();
    String queueName = "aliyun-iot-k1olfsszoYB";
    // 遵循阿里云规范，env设置ak、sk。
    CloudAccount account = new CloudAccount("LTAI5tNhD2KFuLUN1hMEukmS", "dtVF6na8Hp9W8DmAoWI9k24VXwjNyM", "http://1757940634296846.mns.cn-shanghai.aliyuncs.com");
    //this client need only initialize once
    MNSClient client = account.getMNSClient();
    CloudQueue queue = client.getQueueRef(queueName);

    /**
     * 长轮训批量获取消息
     *
     * @param queue
     */
    @SuppressWarnings("InfiniteLoopStatement")
    private static void longPollingBatchReceive(CloudQueue queue) {
        executorService.execute(() -> {
            while (true) {
                log.info("=============开始 长轮训批量获取消息=============");

                // 一次性拉取最多xx条消息
                int batchSize = 15;
                // 长轮询时间为 xx s
                int waitSeconds = 15;

                List<Message> messages = queue.batchPopMessage(batchSize, waitSeconds);
                if (messages != null && !messages.isEmpty()) {
                    for (Message message : messages) {
                        printMsgAndDelete(queue, message);
                    }
                }
                log.info("=============结束 长轮训批量获取消息=============");
            }
        });
    }

    /**
     * 获取单条消息
     *
     * @param queue
     */
    private static void singleReceive(CloudQueue queue) {
        log.info("=============start singleReceive=============");

        Message popMsg = queue.popMessage();
        printMsgAndDelete(queue, popMsg);

        log.info("=============end singleReceive=============");
    }

    /**
     * 删除队列消息
     *
     * @param queue
     * @param popMsg
     */
    private static void printMsgAndDelete(CloudQueue queue, Message popMsg) {
        if (popMsg != null) {
            log.info("message handle: " + popMsg.getReceiptHandle());
            log.info("message body: " + (IS_BASE64 ? popMsg.getMessageBody() : popMsg.getMessageBodyAsRawString()));
            log.info("message id: " + popMsg.getMessageId());
            log.info("message dequeue count:" + popMsg.getDequeueCount());
            //<<to add your special logic.>>

            handleMessage(popMsg.getMessageBodyAsRawString());

            //remember to  delete message when consume message successfully.
            queue.deleteMessage(popMsg.getReceiptHandle());
            log.info("delete message successfully.\n");
        }
    }

    static void handleMessage(String base64) {
        // 对messageBody进行base64解码
        var messageBodyStr = new String(decoder.decode(base64), CharsetUtil.CHARSET_UTF_8);

        // 对messageBodyStr中的payload进行base64解码后转换成MessageBody对象
        var json = JSONObject.parseObject(messageBodyStr);

        json.put("payload", JSONObject.parseObject(new String(decoder.decode(json.get("payload").toString()), CharsetUtil.CHARSET_UTF_8)));
        log.info("消息内容：{}", json.toJSONString());
        if ("upload".equals(json.getString("messagetype"))) {
            var event = json.getJSONObject("payload").getString("event");
                var handler = AwoaraEventHandlerFactory.getEventHandler(event);
                var message = parseMessageBody(json.toJSONString(), Event.getClazz(event));
                handler.handle(message);
        } else {
            log.info("message type is not upload");
        }

    }

    private static <T> MessageBody<T> parseMessageBody(String jsonStr, Class<T> clazz) {
        // 去掉json字符串中的转义符
        var json = StringEscapeUtils.unescapeJava(jsonStr);
        return JSONObject.parseObject(json, new TypeReference<>(clazz) {

        });
    }


    @EventListener(classes = {ContextRefreshedEvent.class})
    @Async
    public void init() {
        longPollingBatchReceive(queue);
    }

}
