package com.usoftchina.qywx.sdk.dto;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author yingp
 */
public class SendMessageReq {

    private final static int MAX_USER_SIZE = 1000;
    private final static int MAX_PARTY_SIZE = 100;
    private final static int MAX_TAG_SIZE = 100;

    private Set<String> userSet;
    private Set<String> partySet;
    private Set<String> tagSet;
    /**
     * 表示是否是保密消息
     */
    private boolean safe;
    /**
     * 表示是否开启id转译
     */
    private boolean enableIdTrans;
    /**
     * 表示是否开启重复消息检查
     */
    private boolean enableDuplicateCheck;
    /**
     * 表示是否重复消息检查的时间间隔
     */
    private Integer duplicateCheckInterval;
    /**
     * 消息类型
     */
    private String type;
    /**
     * 消息内容
     */
    private AbstractMessageBody body;
    /**
     * 企业应用的id
     */
    private Integer agentId;

    public SendMessageReq toUser(String... userIds) {
        if (null == userSet) {
            userSet = new HashSet<>(userIds.length);
        }
        for (String userId : userIds) {
            userSet.add(userId);
        }
        return this;
    }

    public SendMessageReq toParty(Integer... partyIds) {
        if (null == partySet) {
            partySet = new HashSet<>(partyIds.length);
        }
        for (Integer partyId : partyIds) {
            partySet.add(String.valueOf(partyId));
        }
        return this;
    }

    public SendMessageReq toTag(Integer... tagIds) {
        if (null == tagSet) {
            tagSet = new HashSet<>(tagIds.length);
        }
        for (Integer tagId : tagIds) {
            tagSet.add(String.valueOf(tagId));
        }
        return this;
    }

    public SendMessageReq safe(boolean safe) {
        this.safe = safe;
        return this;
    }

    public SendMessageReq enableIdTrans(boolean enableIdTrans) {
        this.enableIdTrans = enableIdTrans;
        return this;
    }

    public SendMessageReq enableDuplicateCheck(boolean enableDuplicateCheck) {
        this.enableDuplicateCheck = enableDuplicateCheck;
        return this;
    }

    public SendMessageReq duplicateCheckInterval(int duplicateCheckInterval) {
        this.duplicateCheckInterval = duplicateCheckInterval;
        return this;
    }

    public SendMessageReq agentId(int agentId) {
        this.agentId = agentId;
        return this;
    }

    public Integer getAgentId() {
        return agentId;
    }

    /**
     * 文本消息
     *
     * @param content
     * @return
     */
    public SendMessageReq text(String content) {
        this.type = "text";
        this.body = new Text(content);
        return this;
    }

    /**
     * 图片消息
     *
     * @param mediaId
     * @return
     */
    public SendMessageReq image(String mediaId) {
        this.type = "image";
        this.body = new Image(mediaId);
        return this;
    }

    /**
     * 语音消息
     *
     * @param mediaId
     * @return
     */
    public SendMessageReq voice(String mediaId) {
        this.type = "voice";
        this.body = new Voice(mediaId);
        return this;
    }

    /**
     * 视频消息
     *
     * @param mediaId
     * @param title
     * @param description
     * @return
     */
    public SendMessageReq video(String mediaId, String title, String description) {
        this.type = "video";
        this.body = new Video(mediaId, title, description);
        return this;
    }

    /**
     * 文件消息
     *
     * @param mediaId
     * @return
     */
    public SendMessageReq file(String mediaId) {
        this.type = "file";
        this.body = new File(mediaId);
        return this;
    }

    /**
     * 文本卡片消息
     *
     * @param title
     * @param description
     * @param url
     * @param btnText
     * @return
     */
    public SendMessageReq textCard(String title, String description, String url, String btnText) {
        this.type = "textcard";
        this.body = new TextCard(title, description, url, btnText);
        return this;
    }

    /**
     * 图文消息
     *
     * @param title
     * @param description
     * @param url
     * @param picUrl
     * @return
     */
    public SendMessageReq news(String title, String description, String url, String picUrl) {
        this.type = "news";
        this.body = new News(title, description, url, picUrl);
        return this;
    }

    /**
     * 存储在企业微信的图文消息
     *
     * @param title
     * @param thumbMediaId
     * @param author
     * @param contentSourceUrl
     * @param content
     * @param digest
     * @return
     */
    public SendMessageReq mpNews(String title, String thumbMediaId, String author, String contentSourceUrl, String content, String digest) {
        this.type = "mpnews";
        this.body = new MpNews(title, thumbMediaId, author, contentSourceUrl, content, digest);
        return this;
    }

    /**
     * markdown消息
     *
     * @param content
     * @return
     */
    public SendMessageReq markdown(String content) {
        this.type = "markdown";
        this.body = new Markdown(content);
        return this;
    }

    /**
     * 任务卡片消息
     *
     * @param title
     * @param description
     * @param url
     * @param taskId
     * @param btns
     * @return
     */
    public SendMessageReq taskCard(String title, String description, String url, String taskId, List<Btn> btns) {
        this.type = "taskcard";
        this.body = new TaskCard(title, description, url, taskId, btns);
        return this;
    }

    public Map<String, Object> build() {
        Map<String, Object> message = new HashMap<>(3);
        message.put("agentid", agentId);
        if (null != userSet) {
            if (userSet.size() > MAX_USER_SIZE) {
                throw new RuntimeException(String.format("最多支持%s个用户", MAX_USER_SIZE));
            }
            message.put("touser", String.join("|", userSet));
        }
        if (null != partySet) {
            if (partySet.size() > MAX_PARTY_SIZE) {
                throw new RuntimeException(String.format("最多支持%s个部门", MAX_PARTY_SIZE));
            }
            message.put("toparty", String.join("|", partySet));
        }
        if (null != tagSet) {
            if (tagSet.size() > MAX_TAG_SIZE) {
                throw new RuntimeException(String.format("最多支持%s个标签", MAX_TAG_SIZE));
            }
            message.put("totag", String.join("|", tagSet));
        }
        if (safe) {
            message.put("safe", 1);
        }
        if (enableIdTrans) {
            message.put("enable_id_trans", 1);
        }
        if (enableDuplicateCheck) {
            message.put("enable_duplicate_check", 1);
        }
        if (null != duplicateCheckInterval) {
            message.put("duplicate_check_interval", duplicateCheckInterval);
        }
        if (null != type) {
            message.put("msgtype", type);
            message.put(type, body.build());
        }
        return message;
    }

    interface AbstractMessageBody {
        Map<String, Object> build();
    }

    class Text implements AbstractMessageBody {
        private final String content;

        public Text(String content) {
            this.content = content;
        }

        @Override
        public Map<String, Object> build() {
            Map<String, Object> data = new HashMap<>(1);
            data.put("content", content);
            return data;
        }
    }

    class Image implements AbstractMessageBody {
        /**
         * 图片媒体文件id，可以调用上传临时素材接口获取
         */
        private final String mediaId;

        public Image(String mediaId) {
            this.mediaId = mediaId;
        }

        @Override
        public Map<String, Object> build() {
            Map<String, Object> data = new HashMap<>(1);
            data.put("media_id", mediaId);
            return data;
        }
    }

    class Voice implements AbstractMessageBody {
        /**
         * 语音文件id，可以调用上传临时素材接口获取
         */
        private final String mediaId;

        public Voice(String mediaId) {
            this.mediaId = mediaId;
        }

        @Override
        public Map<String, Object> build() {
            Map<String, Object> data = new HashMap<>(1);
            data.put("media_id", mediaId);
            return data;
        }
    }

    class Video implements AbstractMessageBody {
        /**
         * 视频媒体文件id，可以调用上传临时素材接口获取
         */
        private final String mediaId;
        private final String title;
        private final String description;

        public Video(String mediaId, String title, String description) {
            this.mediaId = mediaId;
            this.title = title;
            this.description = description;
        }

        @Override
        public Map<String, Object> build() {
            Map<String, Object> data = new HashMap<>(1);
            data.put("media_id", mediaId);
            data.put("title", title);
            data.put("description", description);
            return data;
        }
    }

    class File implements AbstractMessageBody {
        /**
         * 文件id，可以调用上传临时素材接口获取
         */
        private final String mediaId;

        public File(String mediaId) {
            this.mediaId = mediaId;
        }

        @Override
        public Map<String, Object> build() {
            Map<String, Object> data = new HashMap<>(1);
            data.put("media_id", mediaId);
            return data;
        }
    }

    class TextCard implements AbstractMessageBody {
        private final String title;
        private final String description;
        private final String url;
        private final String btnText;

        public TextCard(String title, String description, String url, String btnText) {
            this.title = title;
            this.description = description;
            this.url = url;
            this.btnText = btnText;
        }

        @Override
        public Map<String, Object> build() {
            Map<String, Object> data = new HashMap<>(1);
            data.put("title", title);
            data.put("description", description);
            data.put("url", url);
            data.put("btntxt", btnText);
            return data;
        }
    }

    class News implements AbstractMessageBody {
        private final String title;
        private final String description;
        private final String url;
        private final String picUrl;

        public News(String title, String description, String url, String picUrl) {
            this.title = title;
            this.description = description;
            this.url = url;
            this.picUrl = picUrl;
        }

        @Override
        public Map<String, Object> build() {
            Map<String, Object> data = new HashMap<>(1);
            Map<String, Object> article = new HashMap<>(4);
            article.put("title", title);
            article.put("description", description);
            article.put("url", url);
            article.put("picurl", picUrl);
            data.put("articles", Arrays.asList(article));
            return data;
        }
    }

    class MpNews implements AbstractMessageBody {
        private final String title;
        private final String thumbMediaId;
        private final String author;
        private final String contentSourceUrl;
        private final String content;
        private final String digest;

        public MpNews(String title, String thumbMediaId, String author, String contentSourceUrl, String content, String digest) {
            this.title = title;
            this.thumbMediaId = thumbMediaId;
            this.author = author;
            this.contentSourceUrl = contentSourceUrl;
            this.content = content;
            this.digest = digest;
        }

        @Override
        public Map<String, Object> build() {
            Map<String, Object> data = new HashMap<>(1);
            Map<String, Object> article = new HashMap<>(4);
            article.put("title", title);
            article.put("thumb_media_id", thumbMediaId);
            article.put("author", author);
            article.put("content_source_url", contentSourceUrl);
            article.put("content", content);
            article.put("digest", digest);
            data.put("articles", Arrays.asList(article));
            return data;
        }
    }

    class Markdown implements AbstractMessageBody {
        private final String content;

        public Markdown(String content) {
            this.content = content;
        }

        @Override
        public Map<String, Object> build() {
            Map<String, Object> data = new HashMap<>(1);
            data.put("content", content);
            return data;
        }
    }

    class TaskCard implements AbstractMessageBody {
        private final String title;
        private final String description;
        private final String url;
        private final String taskId;
        private final List<Btn> btns;

        public TaskCard(String title, String description, String url, String taskId, List<Btn> btns) {
            this.title = title;
            this.description = description;
            this.url = url;
            this.taskId = taskId;
            this.btns = btns;
        }

        @Override
        public Map<String, Object> build() {
            Map<String, Object> data = new HashMap<>(1);
            data.put("title", title);
            data.put("description", description);
            data.put("url", url);
            data.put("task_id", taskId);
            data.put("btn", btns.stream().map(Btn::build).collect(Collectors.toList()));
            return data;
        }
    }

    public static class Btn {
        /**
         * 按钮key值，用户点击后，会产生任务卡片回调事件，回调事件会带上该key值，只能由数字、字母和“_-@.”组成，最长支持128字节
         */
        private final String key;
        /**
         * 按钮名称
         */
        private final String name;
        /**
         * 点击按钮后显示的名称，默认为“已处理”
         */
        private final String replaceName;
        /**
         * 按钮字体颜色，可选“red”或者“blue”,默认为“blue”
         */
        private String color;
        /**
         * 按钮字体是否加粗，默认false
         */
        private boolean bold;

        public Btn(String key, String name, String replaceName) {
            this.key = key;
            this.name = name;
            this.replaceName = replaceName;
        }

        public Btn(String key, String name, String replaceName, String color, boolean bold) {
            this.key = key;
            this.name = name;
            this.replaceName = replaceName;
            this.color = color;
            this.bold = bold;
        }

        public Map<String, Object> build() {
            Map<String, Object> data = new HashMap<>(1);
            data.put("key", key);
            data.put("name", name);
            data.put("replaceName", replaceName);
            if (null != color) {
                data.put("color", color);
            }
            if (bold) {
                data.put("is_bold", true);
            }
            return data;
        }
    }
}
