package com.usoftchina.qywx.sdk.dto;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

/**
 * @author yingp
 */
public class SendChatReq {
    /**
     * 群聊id
     */
    private String chatId;
    /**
     * 表示是否是保密消息，0表示否，1表示是，默认0
     */
    private Boolean safe;

    private String type;

    private AbstractMessageBody body;

    public SendChatReq(String chatId) {
        this.chatId = chatId;
    }

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

    /**
     * 文本消息
     *
     * @param content 消息内容，最长不超过2048个字节
     * @return
     */
    public SendChatReq text(String content) {
        this.type = "text";
        this.body = new Text(content);
        return this;
    }

    /**
     * 图片消息
     *
     * @param mediaId 图片媒体文件id，可以调用上传临时素材接口获取
     * @return
     */
    public SendChatReq image(String mediaId) {
        this.type = "image";
        this.body = new Image(mediaId);
        return this;
    }

    /**
     * 语音消息
     *
     * @param mediaId 语音文件id，可以调用上传临时素材接口获取
     * @return
     */
    public SendChatReq voice(String mediaId) {
        this.type = "voice";
        this.body = new Voice(mediaId);
        return this;
    }

    /**
     * 视频消息
     *
     * @param mediaId     视频媒体文件id，可以调用上传临时素材接口获取
     * @param title       视频消息的标题，不超过128个字节，超过会自动截断
     * @param description 视频消息的描述，不超过512个字节，超过会自动截断
     * @return
     */
    public SendChatReq video(String mediaId, String title, String description) {
        this.type = "video";
        this.body = new Video(mediaId, title, description);
        return this;
    }

    /**
     * 文件消息
     *
     * @param mediaId 文件id，可以调用上传临时素材接口获取
     * @return
     */
    public SendChatReq file(String mediaId) {
        this.type = "file";
        this.body = new File(mediaId);
        return this;
    }

    /**
     * 文本卡片消息
     * <p>
     * 卡片消息的展现形式非常灵活，支持使用br标签或者空格来进行换行处理，也支持使用div标签来使用不同的字体颜色，
     * 目前内置了3种文字颜色：灰色(gray)、高亮(highlight)、默认黑色(normal)，将其作为div标签的class属性即可
     * </p>
     *
     * @param title       标题，不超过128个字节，超过会自动截断
     * @param description 描述，不超过512个字节，超过会自动截断
     * @param url
     * @param btnText
     * @return
     */
    public SendChatReq textCard(String title, String description, String url, String btnText) {
        this.type = "textcard";
        this.body = new TextCard(title, description, url, btnText);
        return this;
    }

    /**
     * 文本卡片消息
     * <p>
     * 卡片消息的展现形式非常灵活，支持使用br标签或者空格来进行换行处理，也支持使用div标签来使用不同的字体颜色，
     * 目前内置了3种文字颜色：灰色(gray)、高亮(highlight)、默认黑色(normal)，将其作为div标签的class属性即可
     * </p>
     *
     * @param title       标题，不超过128个字节，超过会自动截断
     * @param description 描述，不超过512个字节，超过会自动截断
     * @param url
     * @return
     */
    public SendChatReq textCard(String title, String description, String url) {
        return textCard(title, description, url, null);
    }

    /**
     * 图文消息
     *
     * @param title       标题，不超过128个字节，超过会自动截断
     * @param description 描述，不超过512个字节，超过会自动截断
     * @param url         点击后跳转的链接。
     * @param picUrl      图文消息的图片链接，支持JPG、PNG格式，较好的效果为大图1068*455，小图150*150。
     * @return
     */
    public SendChatReq news(String title, String description, String url, String picUrl) {
        this.type = "news";
        this.body = new News(title, description, url, picUrl);
        return this;
    }

    /**
     * 图文消息（mpnews）
     * mpnews类型的图文消息，跟普通的图文消息一致，唯一的差异是图文内容存储在企业微信。
     * 多次发送mpnews，会被认为是不同的图文，阅读、点赞的统计会被分开计算。
     *
     * @param title            标题，不超过128个字节，超过会自动截断
     * @param thumbMediaId     图文消息缩略图的media_id, 可以通过素材管理接口获得。此处thumb_media_id即上传接口返回的media_id
     * @param author           图文消息的作者，不超过64个字节
     * @param contentSourceUrl 图文消息点击“阅读原文”之后的页面链接
     * @param content          图文消息的内容，支持html标签，不超过666 K个字节
     * @param digest           图文消息的描述，不超过512个字节，超过会自动截断
     * @return
     */
    public SendChatReq 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消息
     * 目前仅支持markdown语法的子集
     * 微工作台（原企业号）不支持展示markdown消息
     *
     * @param content 消息内容，最长不超过2048个字节
     * @return
     */
    public SendChatReq markdown(String content) {
        this.type = "markdown";
        this.body = new Markdown(content);
        return this;
    }

    public Map<String, Object> build() {
        Map<String, Object> message = new HashMap<>(3);
        message.put("chatid", chatId);
        if (null != safe) {
            message.put("safe", safe ? 1 : 0);
        }
        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 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 {
        private 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 {
        private 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 {
        private String mediaId;
        private String title;
        private 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 {
        private 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 String title;
        private String description;
        private String url;
        private 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<>(4);
            data.put("title", title);
            data.put("description", description);
            data.put("url", url);
            if (null != btnText) {
                data.put("btntxt", btnText);
            }
            return data;
        }
    }

    class News implements AbstractMessageBody {
        private String title;
        private String description;
        private String url;
        private 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<>(1);
            article.put("title", title);
            article.put("description", description);
            article.put("url", url);
            if (null != picUrl) {
                article.put("picurl", picUrl);
            }
            data.put("articles", Arrays.asList(article));
            return data;
        }
    }

    class MpNews implements AbstractMessageBody {
        private String title;
        private String thumbMediaId;
        private String author;
        private String contentSourceUrl;
        private String content;
        private 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<>(1);
            article.put("title", title);
            article.put("thumb_media_id", thumbMediaId);
            if (null != author) {
                article.put("author", author);
            }
            if (null != contentSourceUrl) {
                article.put("content_source_url", contentSourceUrl);
            }
            article.put("content", content);
            if (null != digest) {
                article.put("digest", digest);
            }
            data.put("articles", Arrays.asList(article));
            return data;
        }
    }

    class Markdown implements AbstractMessageBody {
        private 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;
        }
    }
}
