package com.yonge.cooleshow.auth.middleware.wechat.impl;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaMessage;
import cn.binarywang.wx.miniapp.config.WxMaConfig;
import com.alibaba.fastjson.JSON;
import com.google.common.collect.Maps;
import com.microsvc.toolkit.common.tools.ThreadPool;
import com.microsvc.toolkit.middleware.wechat.WxServiceManager;
import com.yonge.cooleshow.auth.api.entity.WxConfigInfo;
import com.yonge.cooleshow.auth.middleware.wechat.MWxMpService;
import com.yonge.cooleshow.auth.middleware.wechat.WxCacheService;
import com.yonge.cooleshow.auth.middleware.wechat.domain.WxConfigStorageWrapper;
import com.yonge.cooleshow.auth.middleware.wechat.domain.WxContentWrapper;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutNewsMessage;
import me.chanjar.weixin.mp.bean.result.WxMpUser;
import me.chanjar.weixin.mp.config.WxMpConfigStorage;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Objects;
import java.util.concurrent.ConcurrentMap;

/**
 * 公众号事件消息通知
 * Created by Eric.Shang on 2/3/17.
 */
@Slf4j
@Service
public class MWxMpServiceImpl implements MWxMpService {

    private final ConcurrentMap<String, WxConfigStorageWrapper> wxMap = Maps.newConcurrentMap();

    @Autowired
    private WxCacheService wxCacheService;

    /**
     * 校验公众号签名
     *
     * @param appid 公众号标识
     * @param timestamp 时间戳
     * @param nonce     随机数
     * @param signature 签名
     * @return boolean
     */
    @Override
    public boolean checkWxMpSignature(String appid, String timestamp, String nonce, String signature) {
        WxMpService wxMpService = WxServiceManager.getInstance().getWxMpService(appid, wxCacheService);
        if (wxMpService == null) {
            log.warn("checkWxMpSignature invalid, appid={}, nonce={} signature={}", appid, nonce, signature);
            return false;
        }
        return wxMpService.checkSignature(timestamp, nonce, signature);

    }

    /**
     * 校验小程序签名
     *
     * @param appid 公众号标识
     * @param timestamp 时间戳
     * @param nonce     随机数
     * @param signature 签名
     * @return boolean
     */
    @Override
    public boolean checkWxMaSignature(String appid, String timestamp, String nonce, String signature) {
        WxMaService wxMaService = WxServiceManager.getInstance().getWxMaService(appid, wxCacheService);
        if (wxMaService == null) {
            log.warn("checkWxMaSignature invalid, appid={}, nonce={} signature={}", appid, nonce, signature);
            return false;
        }
        return wxMaService.checkSignature(timestamp, nonce, signature);

    }

    /**
     * 构造oauth2授权的url连接, 网页授权获取用户基本信息
     * @param appid 公众号标识
     * @param scope 授权类型
     * @param state 状态
     * @param redirectURI 用户授权完成后的重定向链接，无需urlencode, 方法内会进行encode
     * @return String
     */
    @Override
    public String oauth2buildAuthorizationUrl(String appid, String redirectURI, String scope, String state) {
        WxMpService wxMpService = WxServiceManager.getInstance().getWxMpService(appid, wxCacheService);
        if (wxMpService == null) {
            log.warn("oauth2buildAuthorizationUrl invalid, appid={}, url={}, scope={}, state={}", appid, redirectURI,
                    scope, state);
            return "";
        }
        return wxMpService.getOAuth2Service().buildAuthorizationUrl(redirectURI, scope, state);

    }

    /**
     * 用code网页授权获取用户基本信息
     *
     * @param appid 公众号标识
     * @param code 授权code
     * @return String
     * @throws WxErrorException WxErrorException
     */
    @Override
    public String getOAuth2OpenId(String appid, String code) throws WxErrorException {
        WxMpService wxMpService = WxServiceManager.getInstance().getWxMpService(appid, wxCacheService);
        if (wxMpService == null) {
            log.warn("getOAuth2OpenId invalid, appid={}, code={}", appid, code);
            return "";
        }

        return wxMpService.getOAuth2Service().getAccessToken(code).getOpenId();
    }

    /**
     * 根据appid返回配置实例对象
     *
     * @param appid 公众号ID
     * @return WxMpConfigStorage
     */
    @Override
    public WxMpConfigStorage getWxMpConfigStorage(String appid) {

        // 公众号配置信息
        return wxMap.get(appid).getStorage();
    }

    /**
     * 微信路由事件消息
     *
     * @param appId     公众号ID
     * @param inMessage WxMpXmlMessage
     * @return WxMpXmlOutMessage
     */
    @Override
    public WxMpXmlOutMessage route(String appId, WxMpXmlMessage inMessage) {
        if (StringUtils.isEmpty(appId)) {
            log.warn("route invalid appid={}", appId);
            return null;
        }
        if (!wxMap.containsKey(appId)) {
            String wxConfig = wxCacheService.findWxConfigBaseInfo(appId);
            if (StringUtils.isNotEmpty(wxConfig)) {
                wxMap.put(appId, WxConfigStorageWrapper.build().config(wxConfig));
            }
        }
        return wxMap.get(appId).getRouter().route(inMessage);
    }

    /**
     * 关注微信公众号提示信息
     *
     * @param wxMpService WxMpService
     * @param wxMessage WxMpXmlMessage
     * @return WxMpXmlOutMessage
     */
    @Override
    public WxMpXmlOutMessage wxMpSubscribePromptInfo(final WxMpService wxMpService, final WxMpXmlMessage wxMessage) {

        // 查询关注公众号通知消息
        String appId = wxMpService.getWxMpConfigStorage().getAppId();

        // 获取用户信息
        try {
            final WxMpUser wxMpUser = wxMpService.getUserService().userInfo(wxMessage.getFromUser());
            ThreadPool.getExecutor().submit(() -> {

                // 更新公众号关注状态
                wxCacheService.updateMpSubscribeStatusInfo(appId, wxMessage.getFromUser(), wxMpUser.getSubscribe());
            });
        } catch (WxErrorException e) {
            log.error("wxMpSubscribePromptInfo openid={}", wxMessage.getFromUser(), e);
        }

        WxConfigInfo configInfo = wxCacheService.findMPSubscribeNotifyMessageBaseInfo(appId);
        if (Objects.isNull(configInfo) || StringUtils.isBlank(configInfo.getContent())) {
            log.warn("wxMpSubscribePromptInfo invalid req, appid={}", appId);
            return null;
        }
        log.debug("wxMpSubscribePromptInfo appid={}, info={}", appId, JSON.toJSONString(configInfo));
        // 回复图文消息
        WxContentWrapper wrapper = JSON.parseObject(configInfo.getContent(), WxContentWrapper.class);

        return WxMpXmlOutMessage.NEWS().fromUser(wxMessage.getToUser()).toUser(wxMessage.getFromUser())
                .articles(JSON.parseArray(wrapper.getWelcome().toString(), WxMpXmlOutNewsMessage.Item.class)).build();
    }

    /**
     * 修正用户当前位置信息
     *
     * @param wxMessage WxMpXmlMessage
     * @return WxMpXmlOutMessage
     */
    @Override
    public WxMpXmlOutMessage updateUserLocationInfo(WxMpXmlMessage wxMessage) {

        return null;
    }

    /**
     * 用户取消关注事件处理
     *
     * @param wxMessage WxMpXmlMessage
     * @return WxMpXmlOutMessage
     */
    @Override
    public WxMpXmlOutMessage wxMpUnsubscribeInfo(WxMpXmlMessage wxMessage) {

        // 公众号取消关注通知
        wxCacheService.updateMpSubscribeStatusInfo("", wxMessage.getFromUser(), false);

        return null;
    }

    /**
     * 微信扫码消息通知
     *
     * @param wxMessage WxMpXmlMessage
     * @return WxMpXmlOutMessage
     */
    @Override
    public WxMpXmlOutMessage wxScanNotifyInfo(WxMpXmlMessage wxMessage) {
        /*
        * 扫描带参数二维码事件
        *
        * 消息事件类型:
        * https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140454
        * */

        return null;
    }

    /**
     * 微信点击联系我们
     *
     * @param wxMpService WxMpService
     * @param wxMessage WxMpXmlMessage
     * @return WxMpXmlOutMessage
     */
    @Override
    public WxMpXmlOutMessage wxClickEventContactUSInfo(WxMpService wxMpService, WxMpXmlMessage wxMessage) {
        // 查询关注公众号通知消息
        String appid = wxMpService.getWxMpConfigStorage().getAppId();
        WxConfigInfo configInfo = wxCacheService.findMPSubscribeNotifyMessageBaseInfo(appid);
        if (Objects.isNull(configInfo)) {
            log.warn("wxMpSubscribePromptInfo invalid req, appid={}", appid);
            return null;
        }
        WxContentWrapper wrapper = JSON.parseObject(JSON.toJSONString(configInfo), WxContentWrapper.class);
        return WxMpXmlOutMessage.TEXT().fromUser(wxMessage.getToUser()).toUser(wxMessage.getFromUser())
                .content(wrapper.getContact()).build();
    }

    /**
     * 根据appid返回配置实例对象
     * @param appid 公众号ID
     * @return WxMpConfigStorage
     */
    @Override
    public WxMaConfig getWxMaConfigStorage(String appid) {
        // 公众号配置
        return wxMap.get(appid).getMaConfig();
    }

    /**
     * 小程序路由事件消息
     * @param appid 公众号ID
     * @param inMessage WxMpXmlMessage
     */
    @Override
    public void maRoute(String appid, WxMaMessage inMessage) {
        if (StringUtils.isNotEmpty(appid)) {
            if (!wxMap.containsKey(appid)) {
                String wxConfig = wxCacheService.findWxConfigBaseInfo(appid);
                if (StringUtils.isNotEmpty(wxConfig)) {
                    wxMap.put(appid, WxConfigStorageWrapper.build().config(wxConfig));
                }
            }
            wxMap.get(appid).getMaMessageRouter().route(inMessage);
        } else {
            log.warn("route invalid appid={}", appid);
        }
    }

}
