package com.ywt.outpatient.service.rpc.common;

import com.ywt.biz.common.util.serializers.JsonSerializer;
import com.ywt.gapi.ResultCode;
import com.ywt.gapi.message.*;
import com.ywt.outpatient.domain.wechat.Keyword;
import com.ywt.outpatient.service.rpc.BizConfigurer;
import org.apache.dubbo.config.annotation.DubboReference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 微信模板消息发送逻辑类
 */
@Service
public class WeChatMsgProvider {
    private static Logger logger = LoggerFactory.getLogger(WeChatMsgProvider.class);

    @DubboReference
    private WeChatMessageService weChatMessageServiceBlockingStub;

    @Autowired
    BizConfigurer bizConfigurer;

    //定长3线程池
    private static final int NTHREADS = 10;
    private static final ExecutorService exs = Executors.newFixedThreadPool(NTHREADS);

    /**
     * 发送微信小程序模板消息
     *
     * @param terminal   终端编号
     * @param openId     openid
     * @param templateId 模板消息Id
     * @param page       跳转页面
     * @param formId     表单Id
     * @param keywords   关键词
     */
    public void sendToWxApp(int terminal, String openId, String templateId, String page, String formId, String... keywords) {
        try {
            List<SendMPTemplateMessageRequest.Keyword> lst = new LinkedList<>();
            for (String keyword : keywords) {
                SendMPTemplateMessageRequest.Keyword item = SendMPTemplateMessageRequest.Keyword
                        .newBuilder().setValue(keyword).build();
                lst.add(item);
            }

            SendMPTemplateMessageRequest req = SendMPTemplateMessageRequest.newBuilder()
                    .setTerminal(terminal)
                    .setTouser(openId)
                    .setTemplateId(templateId)
                    .setPage(page)
                    .setFormId(formId)
                    .addAllKeywords(lst)
                    .build();
            weChatMessageServiceBlockingStub.sendMPTemplateMessage(req);
        } catch (Exception e) {
            logger.error("sendToWxApp({}, {}, {}, {}, {}, {}): {}", terminal, openId, templateId, page, formId, keywords,
                    e.getMessage(), e);
        }
    }

    /**
     * 发送模板消息
     *
     * @param userId
     * @param tplCode
     * @param url
     * @param miniProgram
     * @param first
     * @param remark
     * @param keywords
     */
    public void send(int userId, String tplCode, String url, String miniProgram,
                     String first, String remark, String... keywords) {
        try {
            Runnable syncRunnable = new Runnable() {
                @Override
                public void run() {
                    Map<String, Object> data = new HashMap<>();
                    data.put("first", new Keyword(first));
                    data.put("remark", new Keyword(remark));

                    for (int i = 0; i < keywords.length; i++) {
                        data.put(String.format("keyword%d", i + 1), new Keyword(keywords[i]));
                    }

                    SendTemplateMessageRequest req = SendTemplateMessageRequest.newBuilder()
                            .setData(JsonSerializer.toJson(data))
                            .setTemplateCode(tplCode)
                            .setUrl(url)
                            .setMiniProgram(miniProgram)
                            .setToUser("")  //openid
                            .setUserId(userId)
                            .build();
                    weChatMessageServiceBlockingStub.sendTemplateMessage(req);
                }
            };
            exs.execute(syncRunnable);
        } catch (Exception e) {
            logger.error("send(): {}", e.getMessage(), e);
        }
    }

    public void sendByTpl1018(
            int userId, String miniProgram, String url, String first, String remark, String keyword1, String keyword2, String keyword3) {
        final String tplCode = "TPL_1018";
        send(userId, tplCode, url, miniProgram, first, remark, keyword1, keyword2, keyword3);
    }

    public void sendByTpl1019(
            int userId, String miniProgram, String url, String first, String remark, String keyword1, String keyword2, String keyword3) {
        final String tplCode = "TPL_1019";
        send(userId, tplCode, url, miniProgram, first, remark, keyword1, keyword2, keyword3);
    }

    public void sendByTpl1022(
            int userId, String miniProgram, String url, String first, String remark, String keyword1, String keyword2, String keyword3) {
        final String tplCode = "TPL_1022";
        send(userId, tplCode, url, miniProgram, first, remark, keyword1, keyword2, keyword3);
    }

    public void sendByTpl1023(
            int userId, String miniProgram, String url, String first, String remark, String keyword1, String keyword2, String keyword3) {
        final String tplCode = "TPL_1023";
        send(userId, tplCode, url, miniProgram, first, remark, keyword1, keyword2, keyword3);
    }

    /**
     * 患者问诊提醒
     */
    public void sendByTpl1029(
            int userId, String first, String remark, String miniProgram, String url, String keyword1, String keyword2) {
        final String tplCode = "TPL_1029";
        send(userId, tplCode, url, miniProgram, first, remark, keyword1, keyword2);
    }

    /**
     * 医务通互联网医院 患者端
     *
     * @param userId
     * @param first
     * @param remark
     * @param miniProgram
     * @param url
     * @param keyword1
     * @param keyword2
     * @param keyword3
     */
    public void sendByTpl1030(
            int userId, String first, String remark, String miniProgram, String url,
            String keyword1, String keyword2, String keyword3) {
        final String tplCode = "TPL_1030";
        send(userId, tplCode, url, miniProgram, first, remark, keyword1, keyword2, keyword3);
    }

    public void sendByTpl1031(
            int userId, String miniProgram, String url, String first, String remark, String keyword1, String keyword2) {
        final String tplCode = "TPL_1031";
        send(userId, tplCode, url, miniProgram, first, remark, keyword1, keyword2);
    }

    public void sendByTpl1032(
            int userId, String miniProgram, String url, String first, String remark,
            String keyword1, String keyword2, String keyword3) {
        final String tplCode = "TPL_1032";
        send(userId, tplCode, url, miniProgram, first, remark, keyword1, keyword2, keyword3);
    }

    public void sendByTpl1033(
            int userId, String miniProgram, String url, String first, String remark,
            String keyword1, String keyword2, String keyword3) {
        final String tplCode = "TPL_1033";
        send(userId, tplCode, url, miniProgram, first, remark, keyword1, keyword2, keyword3);
    }

    public void sendByTpl1034(
            int userId, String miniProgram, String url, String first, String remark,
            String keyword1, String keyword2) {
        final String tplCode = "TPL_1034";
        send(userId, tplCode, url, miniProgram, first, remark, keyword1, keyword2);
    }

    public void sendByTpl1035(
            int userId, String miniProgram, String url, String first, String remark,
            String keyword1, String keyword2, String keyword3) {
        final String tplCode = "TPL_1035";
        send(userId, tplCode, url, miniProgram, first, remark, keyword1, keyword2, keyword3);
    }

    public void sendByTpl1036(
            int userId, String miniProgram, String url, String first, String remark,
            String keyword1, String keyword2, String keyword3) {
        final String tplCode = "TPL_1036";
        send(userId, tplCode, url, miniProgram, first, remark, keyword1, keyword2, keyword3);
    }

    public void sendByTpl1037(
            int userId, String miniProgram, String url, String first, String remark,
            String keyword1, String keyword2) {
        final String tplCode = "TPL_1037";
        send(userId, tplCode, url, miniProgram, first, remark, keyword1, keyword2);
    }

    public void sendByTpl1038(
            int userId, String miniProgram, String url, String first, String remark,
            String keyword1, String keyword2, String keyword3, String keyword4) {
        final String tplCode = "TPL_1038";
        send(userId, tplCode, url, miniProgram, first, remark, keyword1, keyword2, keyword3, keyword4);
    }

    /**
     * 发送模板消息
     * 模板编号：TPL_1039
     * 客户端类型：医务通互联网医院，参考{@link com.ywt.biz.common.enums.TerminalEnum}
     * <p>
     * tpl:
     * {{first.DATA}}
     * 订单号：{{keyword1.DATA}}
     * 配送时间：{{keyword2.DATA}}
     * 收货信息：{{keyword3.DATA}}
     * {{remark.DATA}}
     * <p>
     * eg.
     * 您的处方已开始配送！
     * 订单号：12316549879
     * 配送时间：2018-08-27
     * 收货信息：广州市海珠区（收货人的地址）
     * 请点击查看并支付处方单！
     *
     * @param userId
     * @param miniProgram
     * @param url
     * @param first
     * @param remark
     * @param keyword1
     * @param keyword2
     * @param keyword3
     */
    public void sendByTpl1039(
            int userId, String miniProgram, String url, String first, String remark,
            String keyword1, String keyword2, String keyword3) {
        final String tplCode = "TPL_1039";
        send(userId, tplCode, url, miniProgram, first, remark, keyword1, keyword2, keyword3);
    }

    /**
     * 发送模板消息
     * 模板编号：TPL_1040
     * 客户端类型：医务通互联网医院，参考{@link com.ywt.biz.common.enums.TerminalEnum}
     * <p>
     * tpl:
     * {{first.DATA}}
     * 订单号：{{keyword1.DATA}}
     * 商品名称：{{keyword2.DATA}}
     * {{remark.DATA}}
     * <p>
     * eg.
     * 您的订单已配送完成！
     * 订单号：D2d20170309001
     * 商品名称：药品
     * 完成时间：2018-08-21  18:02
     *
     * @param userId
     * @param first
     * @param remark
     * @param miniProgram
     * @param url
     * @param keyword1
     * @param keyword2
     */
    public void sendByTpl1040(
            int userId, String first, String remark, String miniProgram, String url, String keyword1, String keyword2) {
        final String tplCode = "TPL_1040";
        send(userId, tplCode, url, miniProgram, first, remark, keyword1, keyword2);
    }

    /**
     * 发送模板消息
     * 模板编号：TPL_1041
     * 客户端类型：医务通互联网医院，参考{@link com.ywt.biz.common.enums.TerminalEnum}
     * <p>
     * tpl:
     * {{first.DATA}}
     * 药品内容：{{keyword1.DATA}}
     * 取药地点：{{keyword2.DATA}}
     * 开药医生：{{keyword3.DATA}}
     * {{remark.DATA}}
     * <p>
     * eg.
     * 您好，您的取药信息为：
     * 药品内容：XXX等药品
     * 取药地点：南方医院太和分院
     * 开药医生：张吧医生
     * 请您前往医院取药报到处报道后取药。
     *
     * @param userId
     * @param miniProgram
     * @param url
     * @param first
     * @param remark
     * @param keyword1
     * @param keyword2
     * @param keyword3
     */
    public void sendByTpl1041(
            int userId, String miniProgram, String url, String first, String remark,
            String keyword1, String keyword2, String keyword3) {
        final String tplCode = "TPL_1041";
        send(userId, tplCode, url, miniProgram, first, remark, keyword1, keyword2, keyword3);
    }

    /**
     * 发送模板消息
     * 模板编号：TPL_1042
     * 客户端类型：13，医务通互联网医院医生版，参考{@link com.ywt.biz.common.enums.TerminalEnum}
     * 使用场景：患者收到转诊具体信息，点击“确认”
     * <p>
     * tpl：
     * {{first.DATA}}
     * 患者姓名：{{keyword1.DATA}}
     * 病情描述：{{keyword2.DATA}}
     * 当前状态：{{keyword3.DATA}}
     * {{remark.DATA}}
     * <p>
     * eg.
     * 尊敬的医生，您好！xxx患者确认了转诊！
     * 患者姓名：张三
     * 病情描述：头晕脑胀脖子疼（基层医生写的诊断）
     * 当前状态：确认转诊
     *
     * @param userId
     * @param miniProgram
     * @param url
     * @param first
     * @param remark
     * @param keyword1
     * @param keyword2
     * @param keyword3
     */
    public void sendByTpl1042(
            int userId, String miniProgram, String url, String first, String remark,
            String keyword1, String keyword2, String keyword3) {
        final String tplCode = "TPL_1042";
        send(userId, tplCode, url, miniProgram, first, remark, keyword1, keyword2, keyword3);
    }

    /**
     * 发送模板消息
     * 模板编号：TPL_1043
     * 客户端类型：12，医务通互联网医院患者版，参考{@link com.ywt.biz.common.enums.TerminalEnum}
     * 配药成功，国控返回状态
     * <p>
     * tpl：
     * <p>
     * {{first.DATA}}{{fi
     * 药品内容：{{keyword1.DATA}}
     * 取药地点：{{keyword2.DATA}}
     * 开药医生：{{keyword3.DATA}}
     * {{remark.DATA}}
     * <p>
     * eg.
     * 您好！配药已完成，请及时取药
     * 药品内容：（放上2个药品，后面用“...”表示）
     * 取药地点：生殖中心1楼生殖药房（具体情况请关注药房屏幕提示）
     * 开药医生：黄汉森
     *
     * @param userId
     * @param miniProgram
     * @param url
     * @param first
     * @param remark
     * @param keyword1
     * @param keyword2
     * @param keyword3
     */
    public void sendByTpl1043(int userId, String miniProgram, String url, String first, String remark,
                              String keyword1, String keyword2, String keyword3) {
        final String tplCode = "TPL_1043";
        send(userId, tplCode, url, miniProgram, first, remark, keyword1, keyword2, keyword3);
    }

    /**
     * 发送模板消息
     * 模板编号：TPL_1045
     * 客户端类型：13，医务通互联网医院医生版，参考{@link com.ywt.biz.common.enums.TerminalEnum}
     * 医学界文章提醒
     * <p>
     * tpl：
     * <p>
     * {{first.DATA}}{{fi
     * 用户姓名：{{keyword1.DATA}}
     * 提醒类型：{{keyword2.DATA}}
     * 提醒时间：{{keyword3.DATA}}
     * <p>
     * eg.
     * 您好，xxx医生推荐您看一份发表！
     * 用户姓名：xxx（发表的医生姓名）
     * 提醒类型：《发表的题目》
     * 提醒时间：2017年11月8日 10:11
     */
    public void sendByTpl1045(int userId, String miniProgram, String url, String first, String remark,
                              String keyword1, String keyword2, String keyword3) {
        final String tplCode = "TPL_1045";
        send(userId, tplCode, url, miniProgram, first, remark, keyword1, keyword2, keyword3);
    }

    /**
     * 发送模板消息
     * 模板编号：TPL_1046
     * 客户端类型：12，医务通互联网医院患者版，参考{@link com.ywt.biz.common.enums.TerminalEnum}
     * 医学界文章提醒
     * <p>
     * tpl：
     * <p>
     * {{first.DATA}}{{fi
     * 用户姓名：{{keyword1.DATA}}
     * 提醒类型：{{keyword2.DATA}}
     * 提醒时间：{{keyword3.DATA}}
     * <p>
     * eg.
     * 您好，xxx医生推荐您看一份发表！
     * 用户姓名：xxx（发表的医生姓名）
     * 提醒类型：《发表的题目》
     * 提醒时间：2017年11月8日 10:11
     */
    public void sendByTpl1046(int userId, String miniProgram, String url, String first, String remark,
                              String keyword1, String keyword2, String keyword3) {
        final String tplCode = "TPL_1046";
        send(userId, tplCode, url, miniProgram, first, remark, keyword1, keyword2, keyword3);
    }

    /**
     * 南方医院太和分院 - 预约申请提醒
     * <p>
     * tpl:
     * {{first.DATA}}
     * 姓名：{{keyword1.DATA}}
     * 电话：{{keyword2.DATA}}
     * 期望日期：{{keyword3.DATA}}
     * {{remark.DATA}}
     * <p>
     * eg.
     * 您的远程会诊申请已经通过，预约信息为：
     * 姓名：张倩（患者）
     * 电话：1588888888
     * 期望日期：--
     * 医院：xxxxxx，科室：xxx，医生：xxx，请点击查看并支付订单！
     *
     * @param userId
     * @param miniProgram
     * @param url
     * @param first
     * @param remark
     * @param keyword1
     * @param keyword2
     * @param keyword3
     */
    public void sendByTpl8050(int userId, String miniProgram, String url, String first, String remark,
                              String keyword1, String keyword2, String keyword3) {
        final String tplCode = "TPL_8050";
        send(userId, tplCode, url, miniProgram, first, remark, keyword1, keyword2, keyword3);
    }

    /**
     * 南方医院太和分院 - 订单支付成功通知
     * <p>
     * tpl:
     * {{first.DATA}}{{fi
     * 订单号：{{keyword1.DATA}}
     * 商品详情：{{keyword2.DATA}}
     * 订单金额：{{keyword3.DATA}}
     * {{remark.DATA}}
     * <p>
     * eg.
     * 你好，远程会诊订单支付成功！
     * 订单号：20151001000000001
     * 商品详情：--
     * 订单金额：xx元
     * 3个工作日内将收到远程会诊专家报告！
     *
     * @param userId
     * @param miniProgram
     * @param url
     * @param first
     * @param remark
     * @param keyword1
     * @param keyword2
     * @param keyword3
     */
    public void sendByTpl8051(int userId, String miniProgram, String url, String first, String remark,
                              String keyword1, String keyword2, String keyword3) {
        final String tplCode = "TPL_8051";
        send(userId, tplCode, url, miniProgram, first, remark, keyword1, keyword2, keyword3);
    }

    /**
     * 南方医院太和分院 - 报告生成提醒
     * tpl:
     * {{first.DATA}}
     * 申请时间：{{keyword1.DATA}}
     * 患者姓名：{{keyword2.DATA}}
     * 预约专家：{{keyword3.DATA}}
     * {{remark.DATA}}
     * <p>
     * eg.
     * 您好，您的远程会诊专家报告生成！
     * 申请时间：2015年12月17日16:26:09（下单时间）
     * 患者姓名：刘云华
     * 预约专家：张中  主任医师
     * 请点击查看详情！
     *
     * @param userId
     * @param miniProgram
     * @param url
     * @param first
     * @param remark
     * @param keyword1
     * @param keyword2
     * @param keyword3
     */
    public void sendByTpl8052(int userId, String miniProgram, String url, String first, String remark,
                              String keyword1, String keyword2, String keyword3) {
        final String tplCode = "TPL_8052";
        send(userId, tplCode, url, miniProgram, first, remark, keyword1, keyword2, keyword3);
    }

    /**
     * 南方医院太和分院 - 诊后跟进提醒
     * tpl:
     * <p>
     * {{first.DATA}}
     * 就诊医生：{{keyword1.DATA}}
     * 就诊医院：{{keyword2.DATA}}
     * 姓名：{{keyword3.DATA}}
     * {{remark.DATA}}
     * <p>
     * eg.
     * 您好，您的主诊医生诊后向您发起了诊后提醒
     * 就诊医生：张三
     * 就诊医院：华佗医院
     * 姓名：李四
     * 提醒详情，点击查看！！
     *
     * @param userId
     * @param miniProgram
     * @param url
     * @param first
     * @param remark
     * @param keyword1
     * @param keyword2
     * @param keyword3
     */
    public void sendByTpl8053(int userId, String miniProgram, String url, String first, String remark,
                              String keyword1, String keyword2, String keyword3) {
        final String tplCode = "TPL_8053";
        send(userId, tplCode, url, miniProgram, first, remark, keyword1, keyword2, keyword3);
    }

    /**
     * 南方医院太和分院 - 医生回复通知
     * tpl:
     * {{first.DATA}}
     * 服务医生：{{keyword1.DATA}}
     * 回复时间：{{keyword2.DATA}}
     * {{remark.DATA}}
     * <p>
     * eg.
     * xxx医生有回复
     * 服务医生：xxx
     * 回复时间：2017-10-25
     * 请点击查看
     *
     * @param userId
     * @param miniProgram
     * @param url
     * @param first
     * @param remark
     * @param keyword1
     * @param keyword2
     */
    public void sendByTpl8054(int userId, String miniProgram, String url, String first, String remark,
                              String keyword1, String keyword2) {
        final String tplCode = "TPL_8054";
        send(userId, tplCode, url, miniProgram, first, remark, keyword1, keyword2);
    }

    /**
     * 南方医院太和分院 - 超时退款提醒
     * <p>
     * tpl:
     * {{first.DATA}}{{fi
     * 咨询日期：{{keyword1.DATA}}
     * 医生：{{keyword2.DATA}}
     * 患者：{{keyword3.DATA}}
     * 咨询费用：{{keyword4.DATA}}
     * {{remark.DATA}}
     * <p>
     * eg.
     * 你好，医生超时未回复，问诊费用已退回。
     * 咨询日期：2015-09-12
     * 医生：王宁
     * 患者：张三
     * 咨询费用：
     * 点击查询详情
     *
     * @param userId
     * @param miniProgram
     * @param url
     * @param first
     * @param remark
     * @param keyword1
     * @param keyword2
     * @param keyword3
     * @param keyword4
     */
    public void sendByTpl8055(int userId, String miniProgram, String url, String first, String remark,
                              String keyword1, String keyword2, String keyword3, String keyword4) {
        final String tplCode = "TPL_8055";
        send(userId, tplCode, url, miniProgram, first, remark, keyword1, keyword2, keyword3, keyword4);
    }

    /**
     * 医务通互联网医院医生版 - 收款到账提醒
     * 模板Id：tuS7a8itJoG5a2uiSuzw6NPdZFgrzNX-iF7Gq0Xu0X8
     * <p>
     * {{first.DATA}}
     * 付款人：{{keyword1.DATA}}
     * 交易金额：{{keyword2.DATA}}
     * 收款方式：{{keyword3.DATA}}
     * 交易时间：{{keyword4.DATA}}
     * {{remark.DATA}}
     * <p>
     * 您有一笔收款已到账，请查收！
     * 付款人：李小明（或者微信昵称）
     * 交易金额：30.00
     * 收款方式：互联网医院-我的账户
     * 交易时间：2019-02-04 10:00:00
     *
     * @param userId
     * @param miniProgram
     * @param url
     * @param first
     * @param remark
     * @param keyword1
     * @param keyword2
     * @param keyword3
     * @param keyword4
     */
    public void sendByTpl1055(int userId, String miniProgram, String url, String first, String remark,
                              String keyword1, String keyword2, String keyword3, String keyword4) {
        final String tplCode = "TPL_1055";
        send(userId, tplCode, url, miniProgram, first, remark, keyword1, keyword2, keyword3, keyword4);
    }

    /**
     * 发送小程序订阅消息
     *
     * @param terminal   终端
     * @param openId     openID
     * @param templateId 模版ID
     * @param page       跳转路径
     * @param keywordMap 携带参数
     */
    public void sendMPSubscribeMessage(int terminal, String openId, String templateId, String page, Map<String, String> keywordMap) {
        List<SendMPSubscribeMessageRequest.Keyword> keywordList = new LinkedList<>();
        for (String key : keywordMap.keySet()) {
            SendMPSubscribeMessageRequest.Keyword keyword = SendMPSubscribeMessageRequest.Keyword.newBuilder()
                    .setColor("#000")
                    .setValue(keywordMap.get(key))
                    .setKey(key)
                    .build();
            keywordList.add(keyword);
        }
        SendMPSubscribeMessageRequest req = SendMPSubscribeMessageRequest.newBuilder()
                .setTerminal(terminal)
                .setTouser(openId)
                .setTemplateId(templateId)
                .setPage(page)
                .addAllKeywords(keywordList)
                .build();
        SendMPSubscribeMessageResponse res = weChatMessageServiceBlockingStub.sendMPSubscribeMessage(req);
        if (res.getCode() != ResultCode.SUCCEED_VALUE) {
            logger.info("sendMPSubscribeMessage({})发送失败: {}", req, res.getInfo());
        }
    }

    /**
     * 白云分院 - 预约申请提醒
     */
    public void sendByTpl2011(int userId, String miniProgram, String url, String first, String remark,
                              String keyword1, String keyword2, String keyword3) {
        final String tplCode = "TPL_2011";
        send(userId, tplCode, url, miniProgram, first, remark, keyword1, keyword2, keyword3);
    }

    /**
     * 白云分院 - 咨询反馈通知
     */
    public void sendByTpl2012(int userId, String miniProgram, String url, String first, String remark,
                              String keyword1, String keyword2, String keyword3, String keyword4) {
        final String tplCode = "TPL_2012";
        send(userId, tplCode, url, miniProgram, first, remark, keyword1, keyword2, keyword3, keyword4);
    }

    /**
     * 白云公众号医生版 患者问诊提醒
     */
    public void sendByTpl2013(int userId, String first, String remark, String miniProgram, String url, String keyword1,
                              String keyword2) {
        final String tplCode = "TPL_2013";
        send(userId, tplCode, url, miniProgram, first, remark, keyword1, keyword2);
    }

    /**
     * 白云公众号医生版 医生提醒
     */
    public void sendByTpl2014(int userId, String first, String remark, String miniProgram, String url, String keyword1,
                              String keyword2, String keyword3) {
        final String tplCode = "TPL_2014";
        send(userId, tplCode, url, miniProgram, first, remark, keyword1, keyword2, keyword3);
    }

    /**
     * 白云公众号医生版 收款到账提醒
     */
    public void sendByTpl2015(int userId, String first, String remark, String miniProgram, String url, String keyword1,
                              String keyword2, String keyword3, String keyword4) {
        final String tplCode = "TPL_2015";
        send(userId, tplCode, url, miniProgram, first, remark, keyword1, keyword2, keyword3, keyword4);
    }

    /**
     * 白云公众号医生版 患者问诊提醒
     */
    public void sendByTpl2016(int userId, String first, String remark, String miniProgram, String url, String keyword1,
                              String keyword2) {
        final String tplCode = "TPL_2016";
        send(userId, tplCode, url, miniProgram, first, remark, keyword1, keyword2);
    }
    /**
     * 白云公众号医生版 认证审核通过
     */
    public void sendByTpl2017(int userId, String first, String remark, String miniProgram, String url, String keyword1,
                              String keyword2, String keyword3) {
        final String tplCode = "TPL_2017";
        send(userId, tplCode, url, miniProgram, first, remark, keyword1, keyword2, keyword3);
    }
    /**
     * 白云公众号医生版 认证审核不通过
     */
    public void sendByTpl2018(int userId, String first, String remark, String miniProgram, String url, String keyword1,
                              String keyword2, String keyword3) {
        final String tplCode = "TPL_2018";
        send(userId, tplCode, url, miniProgram, first, remark, keyword1, keyword2, keyword3);
    }
    /**
     * 白云公众号医生版 资料审核结果通知
     */
    public void sendByTpl2019(int userId, String first, String remark, String miniProgram, String url, String keyword1,
                              String keyword2, String keyword3) {
        final String tplCode = "TPL_2019";
        send(userId, tplCode, url, miniProgram, first, remark, keyword1, keyword2, keyword3);
    }
    /**
     * 白云公众号医生版 新处方审核通知
     */
    public void sendByTpl2020(int userId, String first, String remark, String miniProgram, String url, String keyword1,
                              String keyword2, String keyword3, String keyword4) {
        final String tplCode = "TPL_2020";
        send(userId, tplCode, url, miniProgram, first, remark, keyword1, keyword2, keyword3, keyword4);
    }

    public void sendTpl012001(int userId, String tplCode, String url, String miniProgram,
                              Map<String, Object> data){
        try {

            SendTemplateMessageRequest req = SendTemplateMessageRequest.newBuilder()
                    .setData(JsonSerializer.toJson(data))
                    .setTemplateCode(tplCode)
                    .setUrl(url)
                    .setMiniProgram(miniProgram)
                    .setToUser("")  //openid
                    .setUserId(userId)
                    .build();
            weChatMessageServiceBlockingStub.sendTemplateMessage(req);
        } catch (Exception e) {
            logger.error("send(): {}", e.getMessage(), e);
        }

    }

    public void sendTpl012002(int userId, String tplCode, String url, String miniProgram,
                              Map<String, Object> data){
        try {
            SendTemplateMessageRequest req = SendTemplateMessageRequest.newBuilder()
                    .setData(JsonSerializer.toJson(data))
                    .setTemplateCode(tplCode)
                    .setUrl(url)
                    .setMiniProgram(miniProgram)
                    .setToUser("")  //openid
                    .setUserId(userId)
                    .build();
            weChatMessageServiceBlockingStub.sendTemplateMessage(req);
            logger.info("sendTpl012002({}): {}, {}", userId, tplCode);
        } catch (Exception e) {
            logger.error("send(): {}", e.getMessage(), e);
        }
    }

    public void sendTpl013001(int userId, String tplCode, String url, String miniProgram,
                              Map<String, Object> data){
        try {
            SendTemplateMessageRequest req = SendTemplateMessageRequest.newBuilder()
                    .setData(JsonSerializer.toJson(data))
                    .setTemplateCode(tplCode)
                    .setUrl(url)
                    .setMiniProgram(miniProgram)
                    .setToUser("")  //openid
                    .setUserId(userId)
                    .build();
            weChatMessageServiceBlockingStub.sendTemplateMessage(req);
        } catch (Exception e) {
            logger.error("send(): {}", e.getMessage(), e);
        }
    }
}
