package com.nokia.tsl_data.push_message.service;

import com.fasterxml.jackson.databind.JsonNode;
import com.nokia.tsl_data.push_message.properties.PushMessageProperties;

import org.springframework.lang.Nullable;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;
import org.springframework.web.client.RestTemplate;

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

@Service
public class PushMessageService {

    private final PushMessageProperties properties;
    private final RestTemplate restTemplate;

    private final DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");

    public PushMessageService(PushMessageProperties properties, RestTemplate restTemplate) {
        this.properties = properties;
        this.restTemplate = restTemplate;
    }

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

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

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

    /**
     * 发送文本消息
     */
    public void sendTextMessage(String accessToken, String prefix, String message, @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);
        message = message.startsWith(prefix) ? message : prefix + message;
        text.put("CONTENT", message);
        if (atList != null) {
            data.put("AT_LIST", atList);
        }
        if (atAll != null) {
            data.put("AT_ALL", atAll);
        }
        sendMessage(map, accessToken);
    }

    /**
     * 发送markdown消息
     */
    public void sendMarkdownMessage(String accessToken, String prefix, String message) {
        sendMarkdownMessage(accessToken, prefix, message, null, null, null);
    }

    /**
     * 发送markdown消息
     */
    public void sendMarkdownMessage(String accessToken, String prefix, String message, String title) {
        sendMarkdownMessage(accessToken, prefix, message, title, null, null);
    }

    /**
     * 发送markdown消息
     */
    public void sendMarkdownMessage(String accessToken, String prefix, String message, List<Integer> atList) {
        sendMarkdownMessage(accessToken, prefix, message, null, atList, null);
    }

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

    /**
     * 发送markdown消息
     */
    public void sendMarkdownMessage(String accessToken, String prefix, String message, @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", message);
        if (atList != null) {
            data.put("AT_LIST", atList);
        }
        if (atAll != null) {
            data.put("AT_ALL", atAll);
        }
        sendMessage(map, accessToken);
    }

    private void sendMessage(Map<String, Object> reqMap, String accessToken) {
        JsonNode respon = restTemplate.postForObject(properties.getUrl(), getRequest(reqMap, accessToken),
                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, String accessToken) {
        Map<String, Object> map = new HashMap<>();
        map.put("UNI_BSS_HEAD", getUniBssHead());
        map.put("UNI_BSS_BODY", getUniBssBody(reqMap, accessToken));
        return map;
    }

    private Map<String, Object> getUniBssBody(Map<String, Object> reqMap, String accessToken) {
        Map<String, Object> map = new HashMap<>();
        map.put("PUSH_MESSAGE_REQ", reqMap);
        reqMap.put("ACCESS_TOKEN", accessToken);
        reqMap.put("BUSI_CODE", properties.getBusiCode());
        reqMap.put("MODULE_ID", properties.getModuleId());
        reqMap.put("SYSTEM_ID", properties.getSystemId());
        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", properties.getAppId());
        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" + properties.getAppId() + "TIMESTAMP" + timeStamp + "TRANS_ID" + transId
                + properties.getAppSecret();
        return DigestUtils.md5DigestAsHex(beforeEncode.getBytes());
    }

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

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

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