package com.nokia.common.message.pushmessage;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.lang.Nullable;
import org.springframework.web.client.RestTemplate;

import com.fasterxml.jackson.databind.JsonNode;
import com.nokia.common.codec.MD5Util;

import lombok.Builder;

/**
 * 使用RestTemplate调用能力商店钉钉消息推送服务API接口
 * 
 * 此接口实际调用webhook接口的机器人实现
 * 
 * markdown方式使用<font color='red'>内容</font>方式修改字体颜色，在pc端钉钉可生效，在安卓端钉钉上不生效。
 */
@Builder
public class PushMessageUtil {
    // api-url，不增加转发时应该时能力商店的url
    private String url;
    // 能力商店的appid
    private String appId;
    // 能力商店正式环境密钥
    private String appSecret;
    // 系统编号
    private String systemId;
    // 模块编号
    private String moduleId;
    // 业务编码
    private String busiCode;
    // 钉钉群机器人accessToken，通过添加webhook的机器人可以查询到，也可使用已添加的机器人
    private String accessToken;
    // 钉钉机器人前缀
    private String prefix;
    private RestTemplate restTemplate;
    @Builder.Default
    private DateFormat dateFormat1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");

    /**
     * 发送文本消息
     * 
     * @param message
     */
    public void sendTextMessage(String message) {
        sendTextMessage(message, null, null);
    }

    /**
     * 发送文本消息
     * 
     * @param message
     * @param atList
     */
    public void sendTextMessage(String message, @Nullable List<Integer> atList) {
        sendTextMessage(message, atList, null);
    }

    /**
     * 发送文本消息
     * 
     * @param message
     * @param atAll
     */
    public void sendTextMessage(String message, @Nullable Boolean atAll) {
        sendTextMessage(message, null, atAll);
    }

    /**
     * 发送文本消息
     * 
     * @param messge
     * @param atList
     * @param atAll
     */
    public void sendTextMessage(String messge, @Nullable List<Integer> atList, @Nullable Boolean atAll) {
        Map<String, Object> map = new HashMap<>();
        map.put("MSG_TYPE", "text");
        Map<String, Object> data = new HashMap<>();
        map.put("DATA", data);
        Map<String, Object> text = new HashMap<>();
        data.put("TEXT", text);
        messge = messge.startsWith(prefix) ? messge : prefix + messge;
        text.put("CONTENT", messge);
        if (atList != null) {
            data.put("AT_LIST", atList);
        }
        if (atAll != null) {
            data.put("AT_ALL", atAll);
        }
        sendMessage(map);
    }

    /**
     * 发送markdown消息
     * 
     * @param messge
     */
    public void sendMarkdownMessage(String messge) {
        sendMarkdownMessage(messge, null, null, null);
    }

    /**
     * 发送markdown消息
     * 
     * @param messge
     * @param title
     */
    public void sendMarkdownMessage(String messge, String title) {
        sendMarkdownMessage(messge, title, null, null);
    }

    /**
     * 发送markdown消息
     * 
     * @param messge
     * @param atList
     */
    public void sendMarkdownMessage(String messge, List<Integer> atList) {
        sendMarkdownMessage(messge, null, atList, null);
    }

    /**
     * 发送markdown消息
     * 
     * @param messge
     * @param atAll
     */
    public void sendMarkdownMessage(String messge, @Nullable Boolean atAll) {
        sendMarkdownMessage(messge, null, null, atAll);
    }

    /**
     * 发送markdown消息
     * 
     * @param messge
     * @param title
     * @param atList
     * @param atAll
     */
    public void sendMarkdownMessage(String messge, @Nullable String title, @Nullable List<Integer> atList,
            @Nullable Boolean atAll) {
        Map<String, Object> map = new HashMap<>();
        map.put("MSG_TYPE", "markdown");
        Map<String, Object> data = new HashMap<>();
        map.put("DATA", data);
        Map<String, Object> markdown = new HashMap<>();
        data.put("MARK_DOWN", markdown);
        title = title == null || "".equals(title) ? prefix : title;
        title = title.startsWith(prefix) ? title : prefix + title;
        markdown.put("TITLE", title);
        markdown.put("TEXT", messge);
        if (atList != null) {
            data.put("AT_LIST", atList);
        }
        if (atAll != null) {
            data.put("AT_ALL", atAll);
        }
        sendMessage(map);
    }

    private void sendMessage(Map<String, Object> reqMap) {
        JsonNode respon = restTemplate.postForObject(url, getRequest(reqMap), JsonNode.class);
        if (respon == null) {
            throw new RuntimeException("调用结果为空");
        }
        JsonNode node = respon.get("UNI_BSS_HEAD");
        if ("00000".equals(node.get("RESP_CODE").textValue())) {
            node = respon.get("UNI_BSS_BODY").get("PUSH_MESSAGE_RSP");
            if (node != null && "0000".equals(node.get("STATUS").textValue())) {
                node = node.get("RSP");
                if (node != null && "0000".equals(node.get("RSP_CODE").textValue())) {
                    // 只有到这里才说明调用成功了
                    return;
                }
            }
        }
        throw new RuntimeException(respon.toString());
    }

    private Map<String, Object> getRequest(Map<String, Object> reqMap) {
        Map<String, Object> map = new HashMap<>();
        map.put("UNI_BSS_HEAD", getUniBssHead());
        map.put("UNI_BSS_BODY", getUniBssBody(reqMap));
        return map;
    }

    private Map<String, Object> getUniBssBody(Map<String, Object> reqMap) {
        Map<String, Object> map = new HashMap<>();
        map.put("PUSH_MESSAGE_REQ", reqMap);
        reqMap.put("ACCESS_TOKEN", accessToken);
        reqMap.put("BUSI_CODE", busiCode);
        reqMap.put("MODULE_ID", moduleId);
        reqMap.put("SYSTEM_ID", systemId);
        return map;
    }

    private Map<String, Object> getUniBssHead() {
        Map<String, Object> map = new HashMap<>();
        Date date = new Date();
        String timeStamp = getTimeStamp(date);
        String transId = getTransId(date);
        map.put("APP_ID", appId);
        map.put("TIMESTAMP", timeStamp);
        map.put("TRANS_ID", transId);
        map.put("TOKEN", getToken(timeStamp, transId));
        return map;
    }

    private String getToken(String timeStamp, String transId) {
        String beforeEncode = "APP_ID" + appId + "TIMESTAMP" + timeStamp + "TRANS_ID" + transId + appSecret;
        return MD5Util.encode(beforeEncode);
    }

    private String getTransId(Date date) {
        return (new SimpleDateFormat("yyyyMMddHHmmssSSS" + getRandomNumber())).format(date);
    }

    private String getTimeStamp(Date date) {
        return dateFormat1.format(date);
    }

    private int getRandomNumber() {
        return (int) ((Math.random() * 9D + 1D) * 100000D);
    }
}
