package com.kiisoo.ic.wx.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.kiisoo.ic.common.utils.WeixinApi;
import com.kiisoo.ic.config.WxCpConfiguration;
import com.kiisoo.ic.customer.CustomerService;
import com.kiisoo.ic.customer.bean.CustomerDTO;
import com.kiisoo.ic.customer.bean.CustomerModifyDTO;
import com.kiisoo.ic.customer.entity.OpCustomerEnterpriseWechat;
import com.kiisoo.ic.customer.service.CustomerEnterpriseService;
import com.kiisoo.ic.store.entity.PoiStore;
import com.kiisoo.ic.store.mapper.PoiStoreDOMapper;
import com.kiisoo.ic.store.mapper.PoiStoreStaffDOMapper;
import com.kiisoo.ic.store.mapper.PrivilageCpUserStoreDOMapper;
import com.kiisoo.ic.wx.aes.AesException;
import com.kiisoo.ic.wx.aes.WXBizMsgCrypt;
import com.kiisoo.ic.wx.entity.FollowUserDTO;
import com.kiisoo.ic.wx.entity.FollowUserTag;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.cp.api.WxCpService;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.io.StringReader;
import java.util.Date;
import java.util.List;

import static com.kiisoo.ic.config.WxCpConfiguration.APPLICATIONID;

/**
 * @author yechenhao
 * @date 2020/03/16 16:45
 */
@Slf4j
@Service
public class WxResponseService {

    public static final String RES_SUCCESS = "200";
    @Autowired
    private CustomerService customerService;

    @Autowired
    private CustomerEnterpriseService customerEnterpriseService;

    @Autowired
    private QWMailListManageService qwMailListManageService;

    @Autowired
    private PrivilageCpUserStoreDOMapper privilageCpUserStoreDOMapper;

    @Autowired
    private PoiStoreDOMapper poiStoreDOMapper;

    @Autowired
    private PoiStoreStaffDOMapper poiStoreStaffDOMapper;
    /**
     * 获取微信权限验证(认证服务器时使用)
     *
     * @param sVerifyMsgSig    msg_signature参数
     * @param sVerifyTimeStamp timestamp参数
     * @param sVerifyNonce     nonce参数
     * @param sVerifyEchoStr   echostr参数
     * @return 微信认证的url和ticket
     * @author dexiang.jiang
     * @date 2020/03/11 15:44
     */
    public String VerifyURL(String sVerifyMsgSig, String sVerifyTimeStamp, String sVerifyNonce, String sVerifyEchoStr) throws AesException {
        WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(WeixinApi.CUSTOMER_TOKEN, WeixinApi.CUSTOMER_ENCODING_AES_KEY, WeixinApi.CORPID);
        //需要返回的明文
        String sEchoStr;
        sEchoStr = wxcpt.VerifyURL(sVerifyMsgSig, sVerifyTimeStamp, sVerifyNonce, sVerifyEchoStr);
        return sEchoStr;
    }

    /**
     * 解析企业微信返回的数据
     *
     * @param data             xml信息(String)
     * @param sVerifyMsgSig    消息体签名
     * @param sVerifyTimeStamp 时间戳
     * @param sVerifyNonce     随机数字串
     * @return
     * @throws Exception
     */
    public String parse(String sVerifyMsgSig, String sVerifyTimeStamp, String sVerifyNonce, String data) throws Exception {
        WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(WeixinApi.TOKEN, WeixinApi.ENCODING_AES_KEY, WeixinApi.CORPID);
        String sMsg = wxcpt.DecryptMsg(sVerifyMsgSig, sVerifyTimeStamp, sVerifyNonce, data);
        // TODO: 解析出明文xml标签的内容进行处理
        //接单拒单任务的任务返回
//        <xml><ToUserName><![CDATA[wwc8b3e81998fe5394]]></ToUserName>
//        <FromUserName><![CDATA[YeChenHao]]></FromUserName>
//        <MsgType><![CDATA[event]]></MsgType>
//        <Event><![CDATA[taskcard_click]]></Event><
//        CreateTime>1584280168</CreateTime>
//        <EventKey><![CDATA[123-3]]></EventKey>
//        <TaskId><![CDATA[ToDealTask22]]></TaskId>
//        <AgentId>1000037</AgentId></xml>

        //解析xml
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        DocumentBuilder db = dbf.newDocumentBuilder();
        StringReader sr = new StringReader(sMsg);
        InputSource is = new InputSource(sr);
        Document document = db.parse(is);
        Element root = document.getDocumentElement();
        NodeList fromUserNameNode = root.getElementsByTagName("FromUserName");
        String fromUserNameNodeContent = fromUserNameNode.item(0).getTextContent();
        NodeList toUserNameNode = root.getElementsByTagName("FromUserName");
        String toUserNameContent = toUserNameNode.item(0).getTextContent();
        NodeList createTimeNode = root.getElementsByTagName("MsgType");
        String createTimeContent = createTimeNode.item(0).getTextContent();
        NodeList msgTypeNode = root.getElementsByTagName("MsgType");
        String msgTypeContent = msgTypeNode.item(0).getTextContent();

        //根据解析的xml结果执行业务操作，并取得返回内容
        //todo 可封装为私有方法
        String content = "";
        switch (msgTypeContent) {
            case "event":
                NodeList eventNode = root.getElementsByTagName("Event");
                String eventContent = eventNode.item(0).getTextContent();
                switch (eventContent) {
                    case "taskcard_click":
                        NodeList eventKeyNode = root.getElementsByTagName("EventKey");
                        String eventKeyContent = eventKeyNode.item(0).getTextContent();
                        content = toDeal(eventKeyContent);
                        break;
                    default:
                        break;
                }
                break;
            default:
                break;
        }

        if (RES_SUCCESS.equals(content)) {
            //返回结果为200说明无需对客户返回信息
            return content;
        } else {
            //加密要返回的结果(xml形式)
            String sRespData = "<xml><ToUserName><![CDATA[" + fromUserNameNodeContent + "]]></ToUserName>" +
                    "<FromUserName><![CDATA[" + toUserNameContent + "]]></FromUserName>" +
                    "<CreateTime>" + createTimeContent + "</CreateTime>" +
                    "<MsgType><![CDATA[text]]></MsgType>" +
                    "<Content><![CDATA[" + content + "]]></Content>" +
                    "<AgentID>1000037</AgentID></xml>";
            String sEncryptMsg = wxcpt.EncryptMsg(sRespData, sVerifyTimeStamp, sVerifyNonce);
            return sEncryptMsg;
        }
    }

    /**
     * 接单拒单任务卡片的回调
     *
     * @param key 回调选择的值  （订单id-状态）
     * @return 业务操作后的返回
     * @throws IOException
     */
    private String toDeal(String key) throws Exception {
        String[] split = key.split("-");
        Long orderId = Long.valueOf(split[0]);
        Long status = Long.valueOf(split[1]);
//        //todo 加逻辑判断是否已经接单或拒单
//        MyOrderDetailVO orderDetail = myOrderService.getOrderDetail(orderId);
//        if (orderDetail == null) {
//            return "订单不存在";
//        }
//        Integer currentStatus = orderDetail.getStatus();
//        switch (currentStatus) {
//            case 1:
//                return "订单已拒单";
//            case 3:
//                return "订单已接单";
//            default:
//                boolean orderOption = myOrderService.orderOption(orderId, status);
//                switch (split[1]) {
//                    case "1":
//                        if (orderOption) {
//                            return "拒单成功！";
//                        } else {
//                            return "拒单失败！";
//                        }
//                    default:
//                        if (orderOption) {
//                            return "接单成功！";
//                        } else {
//                            return "接单失败！";
//                        }
//                }
//        }

        return "接单成功";

    }

    /**
     * 解析企业微信 通讯录 返回的数据
     *
     * @param data             xml信息(String)
     * @param sVerifyMsgSig    消息体签名
     * @param sVerifyTimeStamp 时间戳
     * @param sVerifyNonce     随机数字串
     * @return
     * @throws Exception
     */
    public String contactHandleParse(String sVerifyMsgSig, String sVerifyTimeStamp, String sVerifyNonce, String data) throws AesException, ParserConfigurationException, IOException, SAXException {
        WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(WeixinApi.CONTACT_TOKEN, WeixinApi.CONTACT_ENCODING_AES_KEY, WeixinApi.CORPID);
        String sMsg = wxcpt.DecryptMsg(sVerifyMsgSig, sVerifyTimeStamp, sVerifyNonce, data);
        //解析xml
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        DocumentBuilder db = dbf.newDocumentBuilder();
        StringReader sr = new StringReader(sMsg);
        InputSource is = new InputSource(sr);
        Document document = db.parse(is);
        Element root = document.getDocumentElement();
        NodeList fromUserNameNode = root.getElementsByTagName("FromUserName");
        String fromUserNameNodeContent = fromUserNameNode.item(0).getTextContent();
        NodeList toUserNameNode = root.getElementsByTagName("ToUserName");
        String toUserNameContent = toUserNameNode.item(0).getTextContent();

        NodeList createTimeNode = root.getElementsByTagName("CreateTime");
        String createTime = createTimeNode.item(0).getTextContent();

        NodeList msgTypeNode = root.getElementsByTagName("MsgType");
        String msgType = msgTypeNode.item(0).getTextContent();

        NodeList eventNode = root.getElementsByTagName("Event");
        String event = eventNode.item(0).getTextContent();

        NodeList changeTypeNode = root.getElementsByTagName("ChangeType");
        String changeType = changeTypeNode.item(0).getTextContent();

        NodeList userIDNode = root.getElementsByTagName("UserID");
        String userID = userIDNode.item(0).getTextContent();

        NodeList nameNode = root.getElementsByTagName("Name");
        String name = nameNode.item(0).getTextContent();

        NodeList mobileNode = root.getElementsByTagName("Mobile");
        String mobile = mobileNode.item(0).getTextContent();


        NodeList xxtAttrNode = root.getElementsByTagName("ExtAttr");
        String item = xxtAttrNode.item(0).getTextContent();
        String item2 = xxtAttrNode.item(1).getTextContent();


        //根据解析的xml结果执行业务操作，并取得返回内容
        //todo 可封装为私有方法
        String content = "";
        if (RES_SUCCESS.equals(content)) {
            //返回结果为200说明无需对客户返回信息
            return content;
        } else {
            //加密要返回的结果(xml形式)
            String sRespData = "<xml><ToUserName><![CDATA[" + fromUserNameNodeContent + "]]></ToUserName>" +
                    "<FromUserName><![CDATA[" + toUserNameContent + "]]></FromUserName>" +
                    "<CreateTime>" + createTime + "</CreateTime>" +
                    "<MsgType><![CDATA[text]]></MsgType>" +
                    "<Content><![CDATA[" + content + "]]></Content>" +
                    "<AgentID>1000037</AgentID></xml>";
            String sEncryptMsg = wxcpt.EncryptMsg(sRespData, sVerifyTimeStamp, sVerifyNonce);
            return sEncryptMsg;
        }
    }

    /**
     * 解析企业微信返回的数据
     *
     * @param data             xml信息(String)
     * @param sVerifyMsgSig    消息体签名
     * @param sVerifyTimeStamp 时间戳
     * @param sVerifyNonce     随机数字串
     * @return
     * @throws Exception
     */
    public String customerParse(String sVerifyMsgSig, String sVerifyTimeStamp, String sVerifyNonce, String data) throws AesException, ParserConfigurationException, IOException, SAXException, WxErrorException {
        WxCpService cpService = WxCpConfiguration.getCpService(APPLICATIONID);
        WXBizMsgCrypt wxcpt = new WXBizMsgCrypt(cpService.getWxCpConfigStorage().getToken(), cpService.getWxCpConfigStorage().getAesKey(), cpService.getWxCpConfigStorage().getCorpId());
        String sMsg = wxcpt.DecryptMsg(sVerifyMsgSig, sVerifyTimeStamp, sVerifyNonce, data);
        log.info(sMsg);
        //解析xml
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        DocumentBuilder db = dbf.newDocumentBuilder();
        StringReader sr = new StringReader(sMsg);
        InputSource is = new InputSource(sr);
        Document document = db.parse(is);
        Element root = document.getDocumentElement();
        NodeList fromUserNameNode = root.getElementsByTagName("FromUserName");
        String fromUserNameNodeContent = fromUserNameNode.item(0).getTextContent();

        NodeList toUserNameNode = root.getElementsByTagName("ToUserName");
        String toUserNameContent = toUserNameNode.item(0).getTextContent();

        NodeList createTimeNode = root.getElementsByTagName("CreateTime");
        String createTimeContent = createTimeNode.item(0).getTextContent();


        NodeList msgTypeNode = root.getElementsByTagName("MsgType");
        String msgTypeContent = msgTypeNode.item(0).getTextContent();

        NodeList eventNode = root.getElementsByTagName("Event");
        String event = eventNode.item(0).getTextContent();

        NodeList changeTypeNode = root.getElementsByTagName("ChangeType");
        String changeType = changeTypeNode.item(0).getTextContent();


        NodeList userIDNode = root.getElementsByTagName("UserID");
        String userID = userIDNode.item(0).getTextContent();

        NodeList externalUserIDNode = root.getElementsByTagName("ExternalUserID");
        String externalUserID = externalUserIDNode.item(0).getTextContent();

        //根据解析的xml结果执行业务操作，并取得返回内容
        String content = "";

        NodeList welcomeCodeNode;
        String welcomeCode;

        switch (changeType) {
            case "edit_external_contact":

                // state字段需要企业成员验证添加后回调给到
                NodeList stateNode2 = root.getElementsByTagName("State");
                if(stateNode2.getLength() > 0) {
                    String state = stateNode2.item(0).getTextContent();
                    log.info(state);
                }
                log.info("add_external_contact 配置了客户联系功能的成员添加外部联系人时，回调该事件");

                // 调用外部联系人详情接口 查看state字段
                String res3 = WeixinApi.getExternalContactInfo(externalUserID);
                log.info(res3);
                editExternalContact(res3);
                break;
            case "add_external_contact":
                // state字段需要企业成员验证添加后回调给到
                NodeList stateNode = root.getElementsByTagName("State");
                if(stateNode.getLength() > 0) {
                    String state = stateNode.item(0).getTextContent();
                    log.info(state);
                }
                log.info("add_external_contact 配置了客户联系功能的成员添加外部联系人时，回调该事件");

                // 调用外部联系人详情接口 查看state字段
                String res = WeixinApi.getExternalContactInfo(externalUserID);
                log.info(res);
                //添加客户并添加店铺企业微信信息
                addExternalContact(res);

//                welcomeCodeNode = root.getElementsByTagName("WelcomeCode");
//                welcomeCode = welcomeCodeNode.item(0).getTextContent();
//
//                sendWelcomeMsg(welcomeCode);

                break;
            case "add_half_external_contact":
//                NodeList stateNode2 = root.getElementsByTagName("State");
//                if(stateNode2.getLength() > 0){
//                    String state2 = stateNode2.item(0).getTextContent();
//                    log.info(state2);
//                }
                log.info("add_half_external_contact 外部联系人添加了配置了客户联系功能且开启了免验证的成员时（此时成员尚未确认添加对方为好友），回调该事件");
                // 调用外部联系人详情接口 查看state字段
                String res2 = WeixinApi.getExternalContactInfo(externalUserID);
                log.info(res2);
                break;
            case "del_external_contact":
                log.info("del_external_contact 配置了客户联系功能的成员删除外部联系人时，回调该事件");
                break;
            case "del_follow_user":
                log.info("del_follow_user 配置了客户联系功能的成员被外部联系人删除时，回调该事件");
                break;
            default:
                welcomeCodeNode = root.getElementsByTagName("WelcomeCode");
                welcomeCode = welcomeCodeNode.item(0).getTextContent();
                log.info("change_external_chat 客户群被修改后（群名变更，群成员增加或移除），回调该事件。收到该事件后，企业需要再调用获取客户群详情接口，以获取最新的群详情。");
                break;
        }

        if (RES_SUCCESS.equals(content)) {
            //返回结果为200说明无需对客户返回信息
            return content;
        } else {
            //加密要返回的结果(xml形式)
            String sRespData = "<xml><ToUserName><![CDATA[" + fromUserNameNodeContent + "]]></ToUserName>" +
                    "<FromUserName><![CDATA[" + toUserNameContent + "]]></FromUserName>" +
                    "<CreateTime>" + createTimeContent + "</CreateTime>" +
                    "<MsgType><![CDATA[text]]></MsgType>" +
                    "<Content><![CDATA[" + content + "]]></Content>" +
                    "<AgentID>1000037</AgentID></xml>";
            String sEncryptMsg = wxcpt.EncryptMsg(sRespData, sVerifyTimeStamp, sVerifyNonce);
            return sEncryptMsg;
        }
    }

    private void sendWelcomeMsg(String welcomeCode) throws WxErrorException {
//        qwMailListManageService.sendWelcomeMsg(welcomeCode);
    }

    /**
     * 解析企业微信返回的客户信息
     * @param
     * @return
     */
    public OpCustomerEnterpriseWechat analyticCustomerEnterprise(String res){
        JSONObject parseObject = JSON.parseObject(res);
        //解析企业微信信息
        OpCustomerEnterpriseWechat ocew = JSONObject.parseObject(parseObject.getString("external_contact"), OpCustomerEnterpriseWechat.class);
        List<FollowUserDTO> fUserDTO = JSONObject.parseArray(parseObject.getString("follow_user"),FollowUserDTO.class);
        if (CollectionUtils.isNotEmpty(fUserDTO)){
            ocew.setUserid(fUserDTO.get(0).getUserid());
            ocew.setRemark(fUserDTO.get(0).getRemark());
            ocew.setDescription(fUserDTO.get(0).getDescription());
            if (null != fUserDTO.get(0).getCreatetime()){
                ocew.setCreatetime(new Date(fUserDTO.get(0).getCreatetime()));
            }
            ocew.setRemarkCorpName(fUserDTO.get(0).getRemark_corp_name());
            ocew.setRemarkMobiles(fUserDTO.get(0).getRemark_mobiles());
            ocew.setState(fUserDTO.get(0).getState());
            List<FollowUserTag> tags  = fUserDTO.get(0).getTags();
            if (CollectionUtils.isNotEmpty(tags)){
                ocew.setTagsGroupName(tags.get(0).getGroup_name());
                ocew.setTagsName(tags.get(0).getTag_name());
                ocew.setTagsType(tags.get(0).getType());
            }
        }
        return ocew;
    }

    /**
     * 添加客户
     * @param res
     */
    public void addExternalContact(String res){
        OpCustomerEnterpriseWechat ocew = analyticCustomerEnterprise(res);
        CustomerDTO customerDTO = new CustomerDTO();
        customerDTO.setUniId(ocew.getUnionid());
        if (StringUtils.isNotBlank(ocew.getState())){
            //解析state 店铺code-导购
            String[] split = ocew.getState().split("-");
            customerDTO.setShopCode(split[0]);
            customerDTO.setStaffCode(split[1]);
        }else{
            String cpuserId = ocew.getUserid();
            Long storeId = privilageCpUserStoreDOMapper.selectOneByCpUserId(cpuserId);
            PoiStore poiStore = poiStoreDOMapper.selectById(storeId);
            customerDTO.setShopCode(poiStore.getCode());
            String staffCode = poiStoreStaffDOMapper.selectShopManagerByShop(storeId);
            customerDTO.setStaffCode(staffCode);
        }
        //调添加客户接口
        Long  customerId = customerService.customerRelation(customerDTO);
        if (null != customerId){
            ocew.setCustomerId(customerId);
            //添加企业外部店铺客户表
            customerEnterpriseService.addCustomerEnterprise(ocew);
        }
    }

    /**
     * 更新客户信息
     * @param res
     */
    public void editExternalContact(String res){
        OpCustomerEnterpriseWechat ocew = analyticCustomerEnterprise(res);
        CustomerModifyDTO customerModifyDTO= new CustomerModifyDTO();
        customerModifyDTO.setUniId(ocew.getUnionid());
        customerModifyDTO.setPhone(ocew.getRemarkMobiles());
        customerModifyDTO.setName(ocew.getName());
         //修改客户信息接口
         customerService.customerVipRelation(customerModifyDTO);
        //添加企业外部店铺客户表
        customerEnterpriseService.editCustomerEnterprise(ocew);
    }
}
