package com.yida.data.common.core.utils;

import cc.mrbird.febs.common.redis.service.RedisService;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.yida.data.common.core.entity.constant.QywxServiceProviderConstant;
import com.yida.data.common.core.exception.FebsException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Map;

/**
 * 企业微信服务商工具类
 *
 * @author ZYJ
 * @date 2022/11/3
 */
@Slf4j
@Component
public class WxServiceProviderUtil {

    /**
     * 企业微信返回码
     */
    public static final String ERR_CODE = "errcode";

    /**
     * 企业微信对返回码的文本描述内容
     */
    public static final String ERR_MESSAGE = "errmsg";

    /**
     * 企业微信接口成功状态码
     */
    public static final String SUCCESS_CODE = "0";

    public static final String ACCESS_TOKEN = "access_token";

    public static final String SUITE_ACCESS_TOKEN = "suite_access_token";

    public static final String PERMANENT_CODE = "permanent_code";

    public static final String PROVIDER_ACCESS_TOKEN = "provider_access_token";

    @Autowired
    private RedisService redisService;

    private static String post(String url, String body) {
        return post(1, url, body);
    }

    private static String post(String url, Map body) {
        return post(1, url, body);
    }

    private static String post(Integer count, String url, String body) {
        if (count <= 3) {
            String res = null;
            try {
                res = HttpUtil.post(url, body);
            } catch (Exception e) {
                log.error("调用企业微信服务商接口异常: {}", e.getMessage(), e);
                if (StrUtil.isNotBlank(e.getMessage()) && e.getMessage().contains("UnknownHostException")) {
                    try {
                        Thread.sleep(500L);
                    } catch (InterruptedException interruptedException) {
                        interruptedException.printStackTrace();
                    }
                    res = post(++count, url, body);
                }
            }
            return res;
        }
        return null;
    }

    private static String post(Integer count, String url, Map body) {
        if (count <= 3) {
            String res = null;
            try {
                res = HttpUtil.post(url, body);
            } catch (Exception e) {
                log.error("调用企业微信服务商接口异常: {}", e.getMessage(), e);
                if (StrUtil.isNotBlank(e.getMessage()) && e.getMessage().contains("UnknownHostException")) {
                    try {
                        Thread.sleep(500L);
                    } catch (InterruptedException interruptedException) {
                        interruptedException.printStackTrace();
                    }
                    res = post(++count, url, body);
                }
            }
            return res;
        }
        return null;
    }

    private static String get(String url, Map params) {
        return get(1, url, params);
    }

    private static String get(Integer count, String url, Map params) {
        if (count <= 3) {
            String res = null;
            try {
                res = HttpUtil.get(url, params);
            } catch (Exception e) {
                log.error("调用企业微信服务商接口异常: {}", e.getMessage(), e);
                if (StrUtil.isNotBlank(e.getMessage()) && e.getMessage().contains("UnknownHostException")) {
                    try {
                        Thread.sleep(500L);
                    } catch (InterruptedException interruptedException) {
                        interruptedException.printStackTrace();
                    }
                    res = get(++count, url, params);
                }
            }
            return res;
        } else {
            return null;
        }
    }

    /**
     * 获取服务商凭证
     *
     * @param corpId         服务商的corpid
     * @param providerSecret 服务商的secret
     * @return java.lang.String
     * @author ZYJ
     * @date 2022/11/9 13:50
     */
    public String getProviderToken(String corpId, String providerSecret) {
        String providerToken = String.valueOf(redisService.get(QywxServiceProviderConstant.PROVIDER_TOKEN + corpId + "." + providerSecret));
        if ("null".equals(providerToken)) {
            // 封装请求参数
            JSONObject jsonObject = JSONUtil.createObj()
                    .set("corpid", corpId)
                    .set("provider_secret", providerSecret);
            // 获取服务商凭证
            String response = post(QywxServiceProviderConstant.GET_PROVIDER_TOKEN_URL, jsonObject.toString());
            JSONObject token = JSONUtil.parseObj(response);
            log.info("企业微信服务商请求provider_token请求参数: {}, 返回值: {}", jsonObject, token);
            if (!token.containsKey(PROVIDER_ACCESS_TOKEN)) {
                throw new FebsException("企业微信服务商请求provider_token失败");
            }
            providerToken = token.get(PROVIDER_ACCESS_TOKEN).toString();
            // 缓存accessToken两小时
            redisService.set(QywxServiceProviderConstant.PROVIDER_TOKEN + corpId + "." + providerSecret, providerToken, 7200L);
        }
        return providerToken;
    }

    /**
     * 获取企业凭证
     *
     * @param authCorpId       授权方corpId
     * @param permanentCode    永久授权码
     * @param suiteAccessToken 第三方应用凭证
     * @return java.lang.String
     * @author ZYJ
     * @date 2022/11/21 17:23
     */
    public String getCorpToken(String authCorpId, String permanentCode, String suiteAccessToken) {
        String corpToken = String.valueOf(redisService.get(QywxServiceProviderConstant.CORP_TOKEN + authCorpId + "." + permanentCode));
        if ("null".equals(corpToken)) {
            // 封装请求参数
            JSONObject jsonObject = JSONUtil.createObj()
                    .set("auth_corpid", authCorpId)
                    .set("permanent_code", permanentCode);
            // 获取企业凭证
            String response = post(QywxServiceProviderConstant.GET_CORP_TOKEN_URL + suiteAccessToken, jsonObject.toString());
            JSONObject token = JSONUtil.parseObj(response);
            log.info("企业微信请求corp_token请求参数: {}, 返回值: {}", jsonObject, token);
            if (!token.containsKey(ACCESS_TOKEN)) {
                throw new FebsException("企业微信请求corp_token失败");
            }
            corpToken = token.get(ACCESS_TOKEN).toString();
            // 缓存accessToken两小时
            redisService.set(QywxServiceProviderConstant.CORP_TOKEN + authCorpId + "." + permanentCode, corpToken, 7200L);
        }
        return corpToken;
    }

    /**
     * 获取第三方应用凭证
     *
     * @param suiteId     第三方应用id或者代开发应用模板id
     * @param suiteSecret 第三方应用secret 或者代开发应用模板secret
     * @param suiteTicket 企业微信后台推送的ticket
     * @return java.lang.String
     * @author ZYJ
     * @date 2022/11/3 15:53
     */
    public String getSuiteAccessToken(String suiteId, String suiteSecret, String suiteTicket) {
        String accessToken = String.valueOf(redisService.get(QywxServiceProviderConstant.SUITE_ACCESS_TOKEN + suiteId + "." + suiteSecret));
        if ("null".equals(accessToken)) {
            // 封装请求参数
            JSONObject jsonObject = JSONUtil.createObj()
                    .set("suite_id", suiteId)
                    .set("suite_secret", suiteSecret)
                    .set("suite_ticket", suiteTicket);
            // 请求微信access token
            String response = post(QywxServiceProviderConstant.GET_SUITE_TOKEN_URL, jsonObject.toString());
            JSONObject token = JSONUtil.parseObj(response);
            log.info("企业微信服务商请求suite_access_token请求参数: {}, 返回值: {}", jsonObject, token);
            if (!token.containsKey(SUITE_ACCESS_TOKEN)) {
                throw new FebsException("企业微信服务商请求suite_access_token失败");
            }
            accessToken = token.get(SUITE_ACCESS_TOKEN).toString();
            // 缓存accessToken两小时
            redisService.set(QywxServiceProviderConstant.SUITE_ACCESS_TOKEN + suiteId + "." + suiteSecret, accessToken, 7200L);
        }
        return accessToken;
    }

    /**
     * 获取企业永久授权码
     *
     * @param suiteAccessToken 第三方应用凭证
     * @param authCode         临时授权码
     * @return cn.hutool.json.JSONObject
     * @author ZYJ
     * @date 2022/11/3 17:55
     */
    public JSONObject getPermanentCode(String suiteAccessToken, String authCode) {
        // 封装请求参数
        JSONObject jsonObject = JSONUtil.createObj().set("auth_code", authCode);

        JSONObject response = JSONUtil.parseObj(post(QywxServiceProviderConstant.GET_PERMANENT_CODE_URL + suiteAccessToken,
                jsonObject.toString()));
        log.info("获取企业服务商永久授权码请求参数: {}, 返回值: {}", jsonObject, response);
        if (!response.containsKey(PERMANENT_CODE)) {
            throw new FebsException("获取企业服务商永久授权码失败");
        }
        return response;
    }

    /**
     * 获取企业授权信息
     *
     * @param suiteAccessToken 第三方应用凭证
     * @param authCorpId       授权方corpid
     * @param permanentCode    永久授权码
     * @return cn.hutool.json.JSONObject
     * @author ZYJ
     * @date 2022/11/7 14:02
     */
    public JSONObject getAuthInfo(String suiteAccessToken, String authCorpId, String permanentCode) {
        // 封装请求参数
        JSONObject jsonObject = JSONUtil.createObj()
                .set("auth_corpid", authCorpId)
                .set("permanent_code", permanentCode);

        JSONObject response = JSONUtil.parseObj(post(QywxServiceProviderConstant.GET_AUTH_INFO_URL + suiteAccessToken,
                jsonObject.toString()));
        log.info("获取企业授权信息请求参数: {}, 返回值: {}", jsonObject, response);
        if (!response.containsKey(PERMANENT_CODE)) {
            throw new FebsException("获取企业授权信息失败");
        }
        return response;
    }

    /**
     * 获取企业授权信息
     *
     * @param suiteAccessToken 第三方应用凭证
     * @param authCode         临时授权码
     * @return cn.hutool.json.JSONObject
     * @author ZYJ
     * @date 2022/11/7 15:11
     */
    public JSONObject getAuthInfoDetail(String suiteAccessToken, String authCode) {
        // 获取企业永久授权码
        JSONObject jsonObject = getPermanentCode(suiteAccessToken, authCode);
        String permanentCode = jsonObject.getStr(PERMANENT_CODE);
        String authCorpId = jsonObject.getJSONObject("auth_corp_info").getStr("corpid");

        return getAuthInfo(suiteAccessToken, authCorpId, permanentCode);
    }

    /**
     * corpId转换
     *
     * @param providerAccessToken 服务商凭证
     * @param corpId              企业ID
     * @return java.lang.String
     * @author ZYJ
     * @date 2022/11/10 9:52
     */
    public String convertCorpId(String providerAccessToken, String corpId) {
        // 封装请求参数
        JSONObject jsonObject = JSONUtil.createObj()
                .set("corpid", corpId);
        JSONObject response = JSONUtil.parseObj(post(QywxServiceProviderConstant.CONVERT_CORP_ID_URL + providerAccessToken,
                jsonObject.toString()));
        log.info("corpId转换请求参数: {}, 返回值: {}", jsonObject, response);
        if (!SUCCESS_CODE.equals(response.containsKey(ERR_CODE) ? response.get(ERR_CODE).toString() : null)) {
            log.error("corpId转换失败，code:{},msg:{},params:{}", response.get(ERR_CODE),
                    response.get(ERR_MESSAGE), jsonObject);
            throw new FebsException("corpId转换失败");
        }
        return response.getStr("open_corpid");
    }

    /**
     * userId转换(单个用户id转换)
     * 将企业主体下的明文userid转换为服务商主体下的密文userid
     *
     * @param accessToken 应用access_token
     * @param userId      成员ID
     * @return java.lang.String
     * @author ZYJ
     * @date 2022/12/1 10:33
     */
    public String convertUserIdToSecret(String accessToken, String userId) {
        JSONArray array = JSONUtil.createArray();
        array.add(userId);
        // 封装请求参数
        JSONObject jsonObject = JSONUtil.createObj()
                .set("userid_list", array);
        JSONObject response = JSONUtil.parseObj(post(QywxServiceProviderConstant.CONVERT_USER_ID_TO_SECRET_URL + accessToken,
                jsonObject.toString()));
        log.info("明文userId转换密文userId请求参数: {}, 返回值: {}", jsonObject, response);
        if (!SUCCESS_CODE.equals(response.containsKey(ERR_CODE) ? response.get(ERR_CODE).toString() : null)) {
            log.error("明文userId转换密文userId失败，code:{},msg:{},params:{}", response.get(ERR_CODE),
                    response.get(ERR_MESSAGE), jsonObject);
            throw new FebsException("明文userId转换密文userId失败");
        }
        // 返回的转换用户id信息
        JSONArray userArray = response.getJSONArray("open_userid_list");
        if (CollUtil.isEmpty(userArray)) {
            log.error("明文userId转换密文userId失败");
            throw new FebsException("明文userId转换密文userId失败");
        }
        Object object = userArray.get(0);
        JSONObject obj = JSONUtil.parseObj(object);
        return obj.getStr("open_userid");
    }

    /**
     * userId的转换
     * 将代开发应用或第三方应用获取的密文open_userid转换为明文userid
     *
     * @param accessToken 企业自建应用或基础应用的调用接口凭证
     * @param userId      成员ID
     * @param agentId     企业授权的代开发自建应用或第三方应用的agentid
     * @return java.lang.String
     * @author ZYJ
     * @date 2023/2/2 10:31
     */
    public String convertUserIdToPlain(String accessToken, String userId, String agentId) {
        JSONArray array = JSONUtil.createArray();
        array.add(userId);
        // 封装请求参数
        JSONObject jsonObject = JSONUtil.createObj()
                .set("open_userid_list", array)
                .set("source_agentid", agentId);
        JSONObject response = JSONUtil.parseObj(post(QywxServiceProviderConstant.CONVERT_USER_ID_TO_PLAIN_URL + accessToken,
                jsonObject.toString()));
        log.info("密文userId转换明文userId请求参数: {}, 返回值: {}", jsonObject, response);
        if (!SUCCESS_CODE.equals(response.containsKey(ERR_CODE) ? response.get(ERR_CODE).toString() : null)) {
            log.error("密文userId转换明文userId失败，code:{},msg:{},params:{}", response.get(ERR_CODE),
                    response.get(ERR_MESSAGE), jsonObject);
            throw new FebsException("密文userId转换明文userId失败");
        }
        // 返回的转换用户id信息
        JSONArray userArray = response.getJSONArray("userid_list");
        if (CollUtil.isEmpty(userArray)) {
            log.error("密文userId转换明文userId失败");
            throw new FebsException("密文userId转换明文userId失败");
        }
        Object object = userArray.get(0);
        JSONObject obj = JSONUtil.parseObj(object);
        return obj.getStr("userid");
    }

    /**
     * 手机号获取userId
     *
     * @param corpAccessToken 企业token
     * @param mobile          手机号
     * @return java.lang.String
     * @author ZYJ
     * @date 2023/2/2 10:25
     */
    public String getUserIdByMobile(String corpAccessToken, String mobile) {
        // 封装请求参数
        JSONObject jsonObject = JSONUtil.createObj()
                .set("mobile", mobile);
        JSONObject response = JSONUtil.parseObj(post(QywxServiceProviderConstant.GET_USER_ID_BY_MOBILE_URL + corpAccessToken,
                jsonObject.toString()));
        log.info("手机号获取userId请求参数: {}, 返回值: {}", jsonObject, response);
        if (!SUCCESS_CODE.equals(response.containsKey(ERR_CODE) ? response.get(ERR_CODE).toString() : null)) {
            log.error("手机号获取userId失败，code:{},msg:{},params:{}", response.get(ERR_CODE),
                    response.get(ERR_MESSAGE), jsonObject);
            throw new FebsException("手机号获取userId失败");
        }
        return "";
    }
}
