package com.boman.wechat.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.boman.common.redis.RedisKey;
import com.boman.common.redis.service.RedisService;
import com.boman.domain.dto.AjaxResult;
import com.boman.domain.form.LoginBody;
import com.boman.wechat.config.WechatProperties;
import com.boman.wechat.service.WechatService;
import com.boman.wechat.utils.HttpClientUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
public class WechatServiceImpl implements WechatService {

    private static final Logger logger = LoggerFactory.getLogger(WechatServiceImpl.class);

    @Resource
    private RedisService redisService;
    @Autowired
    private WechatProperties properties;

    @Override
    public AjaxResult getWechatInfo(LoginBody loginBody) {
        JSONObject infoJsonObject = new JSONObject();
        String code = loginBody.getCode();
        // 获取openId && sessionKey
        String openId = "";
        // 这里的ErrorCodeEnum是自定义错误字段,可以删除,用自己的方式处理
        String sessionKey = "";

        // logger报错的话,删掉就好,或者替换为自己的日志对象
        logger.info("Start get SessionKey,loginRequest的数据为:" + JSONObject.toJSONString(loginBody));
        JSONObject authInfo = null;
        try {
            authInfo = this.getSessionKeyAndOpenId(code);
        }catch (Exception e) {
            return AjaxResult.error(-1, "获取信息失败");
        }
        // 这里的ErrorCodeEnum是自定义错误字段,可以删除,用自己的方式处理
        if(authInfo == null) {
            return AjaxResult.error(-1, "未获取到认证");
        }
        String errMsg = this.validatWechatInfo(authInfo);
        if(StringUtils.isNotEmpty(errMsg)) {
            return AjaxResult.error(-1, errMsg);
        }
        // 获取openId && sessionKey
        openId = authInfo.getString("openid");
        // 这里的ErrorCodeEnum是自定义错误字段,可以删除,用自己的方式处理
        sessionKey = authInfo.getString("session_key");
        // 根据code保存openId和sessionKey
        JSONObject sessionObj = new JSONObject();
        sessionObj.put("openId", openId);
        sessionObj.put("sessionKey", sessionKey);
        // sessionkey 保存到redis
        redisService.setCacheObject(RedisKey.USER_OPPEN_ID_AND_SESSION_KEY_PREFIX, sessionObj.toJSONString(), 10L, TimeUnit.DAYS);
        infoJsonObject.put("unionid", authInfo.get("unionid"));
        infoJsonObject.put("openId", openId);
        infoJsonObject.put("sessionKey", sessionKey);
        return AjaxResult.successZero(infoJsonObject);
    }

    private String validatWechatInfo(JSONObject authInfo) {
        String errMsg = "";
        int errcode =  (Integer) authInfo.get("errcode");
        switch (errcode) {
            case -1:
                errMsg = "系统繁忙,此时请开发者稍候再试";
                break;
            case 40029:
                errMsg = "code 无效";
                break;
            case 41002:
                errMsg = "appId 丢失";
                break;
            case 45011:
                errMsg = "频率限制,每个用户每分钟100次";
                break;
            default:
                errMsg = "信息接口调用未知错误";
                break;
        }
        return errMsg;
    }

    /**
     * 获取小程序验证信息
     * @param code
     * @return
     * @throws Exception
     */
    private JSONObject getSessionKeyAndOpenId(String code) throws Exception {
        Map<String, String> requestUrlParam = new HashMap<>();
        // 小程序appId,自己补充
        requestUrlParam.put("appid", properties.getAppId());
        // 小程序secret,自己补充
        requestUrlParam.put("secret", properties.getSecret());
        // 小程序端返回的code
        requestUrlParam.put("js_code", code);
        // 默认参数
        requestUrlParam.put("grant_type", properties.getGrantType());
        // 发送post请求读取调用微信接口获取openid用户唯一标识
        String result = HttpClientUtils.doGet(properties.getHost(), requestUrlParam);
        return JSON.parseObject(result);
    }
}