package com.zzwtec.wechat.controller;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.jfinal.kit.StrKit;
import com.zzwtec.jdbc.entity.ThirdUserWechat;
import com.zzwtec.jdbc.service.ThirdUserWechatService;
import com.zzwtec.wechat.common.ErrorMsg;
import com.zzwtec.wechat.common.constant.UrlConstants;
import com.zzwtec.wechat.config.WeChatConfig;
import com.zzwtec.wechat.rpc.APIResponse;
import com.zzwtec.wechat.rpc.Signature;
import com.zzwtec.wechat.rpc.api.APIService;
import com.zzwtec.wechat.rpc.inject.ProxyBuilder;
import com.zzwtec.wechat.sdk.api.AccessTokenApi;
import com.zzwtec.wechat.sdk.api.ApiConfigKit;
import com.zzwtec.wechat.sdk.api.ApiResult;
import com.zzwtec.wechat.sdk.api.TemplateMsgApi;
import com.zzwtec.wechat.util.CharUtil;
import com.zzwtec.wechat.util.security.MyBase64Util;
import com.zzwtec.wechat.util.security.TokenUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static com.zzwtec.wechat.common.enums.UserCellType.MASTER;
import static com.zzwtec.wechat.common.enums.UserCellType.MEMBER;
import static com.zzwtec.wechat.common.enums.UserCellType.TENANT;
import static com.zzwtec.wechat.sdk.utils.RenderUtil.renderText;

/**
 * 微信消息
 * 请求微信把消息发送给用户
 * @author 邓燎燕
 *         2016年5月9日
 */
@Controller
@RequestMapping("/push")
public class WechatMsgController{
    private static final Logger logger = LoggerFactory.getLogger(WechatMsgController.class);
    private static final ExecutorService executorService = Executors.newWorkStealingPool();
    @Autowired
    private static final APIService apiService = ProxyBuilder.build(APIService.class,WeChatConfig.weChatConfig);
    @Autowired
    private HttpServletRequest request;
    @Autowired
    private ThirdUserWechatService thirdUserWechatService;

    /**
     * 处理旧的请求
     * @param body
     * @return
     */
    private String oldRequest(String body){
        if(body.startsWith("msg=")){
            body = body.substring("msg=".length());
            try {
                body = URLDecoder.decode(body,"UTF-8");
            } catch (UnsupportedEncodingException e) {
                return null;
            }
        }
        return body;
    }

    /**
     * 发公告模版消息 <br>
     * 请求msg 值:{"token":"token","openid":["openid"],"msgid":"公告ID","msgtitle":"公告标题","msgtime":"公告发布时间","msgcontent":"公告简述"} <br>
     * openid 微信用户的openid数组 <br>
     * msgid 公告ID <br>
     * msgtitle 公告标题 <br>
     * msgtime 公告发布时间 如“5月11日 18:00:00” <br>
     * msgcontent 公告简述 公告内容的请20个字加省略号
     */
    @RequestMapping(value = "/cmsg",produces = "application/json",method = RequestMethod.POST)
    @ResponseBody
    public JSONObject msg(@RequestBody String body) {
        logger.info("公告推送："+body);
        // 验证数据合法性
//        if (!validateSign(body)) {
//            return returnFail("10", ErrorMsg._10);
//        }

        // 验证数据有效性
        body = oldRequest(body);
        if(body==null){
            return returnFail();
        }
        JSONObject json = JSONObject.parseObject(body);
        if (json == null) {
            return returnFail();
        }
        final JSONArray openidArr = json.containsKey("openids")?json.getJSONArray("openids"):json.getJSONArray("openid");
        final String msgid = json.getString("msgid");
        final String msgtitle = json.getString("msgtitle");
        final String msgtime = json.getString("msgtime");
        final String msgcontent = json.getString("msgcontent");
        if (openidArr == null || openidArr.isEmpty()
                || StringUtils.isEmpty(msgid) || StringUtils.isEmpty(msgtitle) || StringUtils.isEmpty(msgtime) || StringUtils.isEmpty(msgcontent)) {

            return returnFail();
        }

        /*
         * 使用了 物业管理通知 模板
         *
         * {{first.DATA}}
         * 标题：{{keyword1.DATA}}
         * 发布时间：{{keyword2.DATA}}
         * 内容：{{keyword3.DATA}}
         * {{remark.DATA}}
         */

        if(WeChatConfig.weChatConfig.isPush()){
            executorService.execute(() -> {

                JSONObject template = new JSONObject();
                JSONObject data = new JSONObject();

                String url, title;
                Pattern pattern = Pattern.compile("^\\[(.*)\\]\\((.*)\\)$");
                Matcher matcher = pattern.matcher(msgtitle);
                if (matcher.find()) {
                    title = matcher.group(1);
                    url = matcher.group(2);
                } else {
                    title = msgtitle;
                    url = WeChatConfig.weChatConfig.getHost() + UrlConstants.MSG_GET_MSG + "/" + msgid;
                }

//                template.put("template_id", "uDkGCbdRYeQHEeebwYMcpFCviFhrS-VZdUFqaLgWi14");
                template.put("template_id", WeChatConfig.weChatConfig.getNoticeTemplateId());
                template.put("topcolor", "#E93C1F");
                template.put("url", url);
                template.put("data", data);

                data.put("first", new JSONObject().fluentPut("value", "公告").fluentPut("color", "#000000"));
                data.put("keyword1", new JSONObject().fluentPut("value", title).fluentPut("color", "#000000"));
                data.put("keyword2", new JSONObject().fluentPut("value", msgtime).fluentPut("color", "#000000"));
                data.put("keyword3", new JSONObject().fluentPut("value", msgcontent).fluentPut("color", "#000000"));
                data.put("remark", new JSONObject().fluentPut("value", "点击查看公告详情。").fluentPut("color", "#000000"));

                for (int i = 0; i < openidArr.size(); i++) {
                    String openid = openidArr.getString(i);
                    template.put("touser", openid);
                    String templateStr = template.toJSONString();
                    sendTemplateMsg(templateStr);
                }
            });
        }



       return returnOk();
    }

    /**
     * 发门铃呼叫模版消息 <br>
     * 请求msg 值:{"token":"token","openid":["openid"],"room":"快照房间","callname":"呼叫来源","calltime":"呼叫时间"} <br>
     * openid 微信用户的openid数组 <br>
     * room 快照房间 <br>
     * callname 呼叫来源 <br>
     * calltime 呼叫时间 如“5月11日 18:00:00”
     */
    @RequestMapping(value = "/doorbell",produces = "application/json",method = RequestMethod.POST)
    @ResponseBody
    public JSONObject doorbell(@RequestBody String body) {
        logger.info("呼叫推送："+body);
        // 验证数据合法性
//        if (!validateSign(body)) {
//
//            return returnFail("10", ErrorMsg._10);
//        }
        // 验证数据有效性
        body = oldRequest(body);
        if(body==null){
            return returnFail();
        }
        JSONObject json = JSONObject.parseObject(body);
        if (json == null) {
            return returnFail();
        }
        List<String> openidArr = new ArrayList<>();
        String room = json.getString("room");
        String callname = json.getString("callname");
        String calltime = json.getString("calltime");

        //房间id 根据房间id查询相关用户openid
        String cellId = json.getString("cellId");

        APIResponse userCellResponse = apiService.queryUserAndCellByCellId(cellId);
        if (userCellResponse.isFail()) {
            renderText(userCellResponse.getMsg());
            return null;
        }
        // 房间住户信息
        JSONArray userCells = JSONArray.parseArray(userCellResponse.getData());
        if(userCells!=null){
            List<String> userIds=new ArrayList<>();
            userCells.stream().forEach(obj ->{
                JSONObject userCell = (JSONObject) obj;
                userIds.add(userCell.getString("userId"));
            });

            List<ThirdUserWechat> thirdUserWechats=thirdUserWechatService.queryUserWechatByUserIds(userIds);
            if(thirdUserWechats!=null){
                thirdUserWechats.stream().forEach(thirdUserWechat ->{
                    openidArr.add(thirdUserWechat.getOpenid());
                });
            }
        }


        if (openidArr == null || openidArr.isEmpty()
                || StringUtils.isEmpty(room) || StringUtils.isEmpty(callname) || StringUtils.isEmpty(calltime)) {

            return returnFail();
        }

        /*
         * 使用了 来访提醒 模板
         * {{first.DATA}}
         * 访客：{{keyword1.DATA}}
         * 来访事由：{{keyword2.DATA}}
         * 联系电话：{{keyword3.DATA}}
         * 到达时间：{{keyword4.DATA}}
         * {{remark.DATA}}
         */
        if(WeChatConfig.weChatConfig.isPush()){
            executorService.execute(() -> {
                JSONObject template = new JSONObject();
                JSONObject data = new JSONObject();
//                template.put("template_id","FQECzlCRIk3UQb-MOfABs8Cu9vQMmR1E5hxbqrZgOKw");
                template.put("template_id", WeChatConfig.weChatConfig.getVisitTemplateId());
                template.put("topcolor", "#E93C1F");
                template.put("data", data);

                data.put("first", new JSONObject().fluentPut("value", "您有一个访客到访。").fluentPut("color", "#EB4324"));
                data.put("keyword1", new JSONObject().fluentPut("value", "点击查看").fluentPut("color", "#EB4324"));
                data.put("keyword2", new JSONObject().fluentPut("value", "到访").fluentPut("color", "#000000"));
                data.put("keyword3", new JSONObject().fluentPut("value", "无").fluentPut("color", "#000000"));
                data.put("keyword4", new JSONObject().fluentPut("value", calltime).fluentPut("color", "#EB4324"));
                data.put("remark", new JSONObject().fluentPut("value", "点击查看访客信息，确认访客身份。").fluentPut("color", "#000000"));

                for (int i = 0; i < openidArr.size(); i++) {
                    String openid = openidArr.get(i);
                    template.put("touser", openid);
                    template.put("url", WeChatConfig.weChatConfig.getHost()+ UrlConstants.DOORBELL_CALLROOM + "/" + room.replaceAll("-", "_") + "/" + callname.replaceAll("-", "_") + "/" + openid);
                    String templateStr = template.toJSONString();
                    logger.info("发门铃呼叫模版消息: "+templateStr);
                    sendTemplateMsg(templateStr);
                }

            });
        }


      return  returnOk();
    }

    /**
     * 发开门反馈模版消息 门口机或围墙机的门铃设备调用
     * e 加密信息
     * token
     * type
     * opentime 开门反馈时间
     * doorname 开门名称
     * openres 开门结果： 开锁成功 开锁失败
     */
    @RequestMapping(value = "/dooropen",produces = "application/json",method = RequestMethod.POST)
    @ResponseBody
    public JSONObject pushOpenDoorMsg(String e,@RequestBody(required = false) JSONObject json) {
        logger.info("开门反馈推送："+(json==null?"":json.toJSONString()));
        String opentime;
        String doorname;
        String openres;
        //兼容之前的版本,如果json为空说明客户端的提交方式是表单
        if(json == null){
            opentime = request.getParameter("opentime");
            doorname = request.getParameter("doorname");
            openres = request.getParameter("openres");
        }else{
            opentime = json.getString("opentime");
            doorname = json.getString("doorname");
            openres = json.getString("openres");
        }

        if (StrKit.isBlank(e)) {
            return returnFail();
        }
        // appId&openid&doorId&nowTime
        String decode = MyBase64Util.decode(e);
        if (decode == null) {
            return returnFail();
        }
        String[] paras = decode.split(CharUtil.PARA_SEPARATE);
        if (paras.length != 5) {
            return returnFail();
        }
        if (!paras[0].equals(ApiConfigKit.getAppId())) {
            return returnFail();
        }
        if (DoorbellController.isTimeout(paras[3])) {
            return returnFail();
        }
        if (TokenUtil.isValid(paras[4])) {
            return returnFail();
        }
        if (StringUtils.isEmpty(opentime) || StringUtils.isEmpty(doorname) || StringUtils.isEmpty(openres)) {
            return returnFail();
        }

        /*
         * 使用了 监控被触发提醒 模板
         *
         * {{first.DATA}}
         * 触发时间：{{keyword1.DATA}}
         * 触发类型：{{keyword2.DATA}}
         * 触发详情：{{keyword3.DATA}}
         * {{remark.DATA}}
         */

        String finalDoorname = doorname;
        String finalOpenres = openres;
        String finalOpentime = opentime;

        if(WeChatConfig.weChatConfig.isPush()){
            executorService.execute(() -> {

                JSONObject template = new JSONObject();
                JSONObject data = new JSONObject();
                template.put("touser", paras[1]);
//                template.put("template_id", "akEk5yB02eC9-IhIzj5hpZz_asHK4_g9b-per4PzSKM");
                template.put("template_id", WeChatConfig.weChatConfig.getFeedbackTemplateId());
                template.put("topcolor", "#E93C1F");
                template.put("url", WeChatConfig.weChatConfig.getHost()+UrlConstants.INFO_FEEDBACKDETAIL);
                template.put("data", data);

                data.put("first", new JSONObject().fluentPut("value", finalDoorname + " " + finalOpenres).fluentPut("color", "#EB4324"));
                data.put("keyword1", new JSONObject().fluentPut("value", finalOpentime).fluentPut("color", "#EB4324"));
                data.put("keyword2", new JSONObject().fluentPut("value", "开锁反馈").fluentPut("color", "#000000"));
                data.put("keyword3", new JSONObject().fluentPut("value", finalDoorname + " " + finalOpenres).fluentPut("color", "#000000"));
                data.put("remark", new JSONObject().fluentPut("value", "").fluentPut("color", "#000000"));

                sendTemplateMsg(template.toJSONString());
               /* JSONArray news = null;
                try {
                    //获取微信广告
                    APIResponse apiResponse = apiService.queryWechatNewsAll();
                    //广告列表
                    String newsJson = apiResponse.getData();
                    news = null;
                    if(StrKit.notBlank(newsJson)){
                        news = JSON.parseArray(newsJson);
                    }
                } catch (Exception e1) {
                    logger.error("出现异常!",e1);
                }
                //用户OPENID
                String openId = paras[1];

                List<CustomServiceApi.Articles> articleList = new ArrayList<CustomServiceApi.Articles>(){
                    {
                        CustomServiceApi.Articles main = new CustomServiceApi.Articles();
                        main.setTitle("开锁成功!");
                        add(main);
                    }
                };

                if(news != null && !news.isEmpty()){
                    for (int i = 0; i < news.size(); i++) {
                        JSONObject jsonObject = news.getJSONObject(i);
                        String title = jsonObject.getString("title");
                        String url = jsonObject.getString("url");
                        String img = jsonObject.getString("img");
                        CustomServiceApi.Articles article = new CustomServiceApi.Articles();
                        article.setTitle(title);
                        article.setUrl(url);
                        article.setPicurl(img);
                        articleList.add(article);
                    }
                }else{
                    CustomServiceApi.Articles article = new CustomServiceApi.Articles();
                    article.setTitle("智之屋官网");
                    article.setUrl("http://www.zzwtec.com/");
                    article.setPicurl("http://wechat.zzwtec.com/images/logo.png");
                    articleList.add(article);
                }


                ApiResult apiResult = CustomServiceApi.sendNews(openId, articleList);
                if(!apiResult.isSucceed()){
                    logger.error("发送客服消息,出现异常!" + apiResult.getErrorMsg());
                }*/
            });


        }


        return returnOk();
    }

    /**
     * 发送模板消息
     *
     * @param templateStr 消息模板
     */
    private static void sendTemplateMsg(String templateStr) {
        ApiConfigKit.setThreadLocalAppId(ApiConfigKit.getAppId());
        ApiResult apiResult;
        int i = 0;
        AccessTokenApi.refreshAccessToken();
        do {
            if (i >= 5) {
                break;
            }
            apiResult = TemplateMsgApi.send(templateStr);
            if (!apiResult.isSucceed()) {
                logger.error("sendTemplateMsg Faile:\nErrorCode:" +apiResult.getErrorCode()+"\nErrorMsg:"+apiResult.getErrorMsg()+"\ntemplateStr:"+templateStr);
                if(43004 == apiResult.getErrorCode()){ // 需要接收者关注
                    break;
                }
                i++;
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            } else {
                logger.debug("sendTemplateMsg Succeed");
                break;
            }
        } while (!apiResult.isSucceed());
    }

    /**
     * 回复操作正常
     */
    private JSONObject returnOk() {
        JSONObject json = JSONObject.parseObject("{}");
        json.put("error", "0");
        json.put("errormsg", ErrorMsg._0);
        return json;
    }

    /**
     * 回复操作失败
     */
    private JSONObject returnFail() {
        JSONObject json = JSONObject.parseObject("{}");
        json.put("error", "415");
        json.put("errormsg", ErrorMsg._415);
        return json;
    }

    private JSONObject returnFail(String code, String msg) {
        JSONObject json = new JSONObject();
        json.put("error", code);
        json.put("errormsg", msg);
        return json;
    }

    private boolean validateSign(String body) {
        String header = request.getHeader(Signature.ZZW_SIGN_HEADER);
        Signature signature = Signature.parseHeader(header);
        if (signature == null) {
            return false;
        }
        signature.setSecretKey(WeChatConfig.weChatConfig.getZzwtecSecretKey());
        return signature.validateSign(body);
    }
}
