package com.fjhx.dingding.utils;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.aliyun.dingtalkoauth2_1_0.Client;
import com.aliyun.dingtalkoauth2_1_0.models.GetCorpAccessTokenRequest;
import com.aliyun.dingtalkoauth2_1_0.models.GetCorpAccessTokenResponseBody;
import com.aliyun.tea.TeaException;
import com.aliyun.teaopenapi.models.Config;
import com.dingtalk.api.DefaultDingTalkClient;
import com.dingtalk.api.DingTalkClient;
import com.dingtalk.api.request.OapiV2DepartmentListsubRequest;
import com.dingtalk.api.request.OapiV2UserGetRequest;
import com.dingtalk.api.request.OapiV2UserGetuserinfoRequest;
import com.dingtalk.api.response.OapiV2DepartmentListsubResponse;
import com.dingtalk.api.response.OapiV2UserGetResponse;
import com.dingtalk.api.response.OapiV2UserGetuserinfoResponse;
import com.fjhx.dingding.constant.Constant;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.system.utils.ConfigUtil;
import com.taobao.api.ApiException;
import lombok.extern.slf4j.Slf4j;

import java.util.List;
import java.util.concurrent.TimeUnit;


/**
 * 钉钉第三方企业应用 - h5微应用
 *
 * <p>
 * <a href="https://open.dingtalk.com/document/isvapp/basic-concepts"> 基础概念 </a>
 * <a href="https://open.dingtalk.com/document/isvapp/api-overview"> 钉钉api总览 </a>
 * <a href="https://open.dingtalk.com/document/isvapp/third-party-enterprise-application-logon-free"> 免登流程 </a>
 * </p>
 */

@Slf4j
public class DingUtil {

    private static final RedisCache redisCache = SpringUtil.getBean(RedisCache.class);
    private static final String corpAccessTokenRedisKey = "corpAccessToken:";

    /**
     * 获取第三方应用授权企业的accessToken
     * https://open.dingtalk.com/document/isvapp/obtain-the-access_token-of-the-authorized-enterprise
     */
    public static String getCorpAccessToken(String corpId) {

        String redisKey = corpAccessTokenRedisKey + corpId;
        String corpAccessToken = redisCache.getCacheObject(redisKey);
        if (StrUtil.isNotBlank(corpAccessToken)) {
            return corpAccessToken;
        }

        String suiteTicket = ConfigUtil.get("dd_suite_ticket");

        if (StrUtil.isBlank(suiteTicket)) {
            throw new ServiceException("没有找到suite_ticket");
        }

        GetCorpAccessTokenRequest getCorpAccessTokenRequest = new GetCorpAccessTokenRequest()
                .setSuiteKey(Constant.SUITE_KEY)
                .setSuiteSecret(Constant.SUITE_SECRET)
                .setAuthCorpId(corpId)
                .setSuiteTicket(suiteTicket);

        try {
            Client client = getClient2();
            GetCorpAccessTokenResponseBody body = client.getCorpAccessToken(getCorpAccessTokenRequest).getBody();
            redisCache.setCacheObject(redisKey, body.getAccessToken(), Convert.toInt(body.getExpireIn() - 60), TimeUnit.SECONDS);
            return body.getAccessToken();
        } catch (Exception e) {

            TeaException teaException;

            if (e instanceof TeaException) {
                teaException = (TeaException) e;
            } else {
                teaException = new TeaException(e.getMessage(), e);
            }

            String errCode = teaException.getCode();
            String errMsg = teaException.getMessage();

            if (StrUtil.isAllNotBlank(errCode, errMsg)) {
                log.error("钉钉授权认证失败： code：{}，message：{}", errCode, errMsg);
                throw new ServiceException(errMsg);
            } else {
                log.error("钉钉授权认证失败", teaException);
                throw new ServiceException("发生未知异常，钉钉授权认证失败");
            }

        }
    }

    /**
     * 通过免登码获取用户信息
     * https://open.dingtalk.com/document/isvapp/obtain-the-userid-of-a-user-by-using-the-log-free
     */
    public static OapiV2UserGetuserinfoResponse.UserGetByCodeResponse getUserInfo(String corpId, String code) {
        try {
            DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/user/getuserinfo");
            OapiV2UserGetuserinfoRequest req = new OapiV2UserGetuserinfoRequest();
            req.setCode(code);
            String corpAccessToken = getCorpAccessToken(corpId);
            OapiV2UserGetuserinfoResponse rsp = client.execute(req, corpAccessToken);
            OapiV2UserGetuserinfoResponse.UserGetByCodeResponse result = rsp.getResult();
            if (result == null) {
                log.error(rsp.getErrmsg());
                throw new ServiceException(rsp.getErrmsg());
            }
            return result;
        } catch (Exception e) {
            log.error("通过免登码获取用户信息失败", e);
            throw new ServiceException("通过免登码获取用户信息失败");
        }
    }

    public static OapiV2UserGetResponse.UserGetResponse getUserDetail(String corpId, String userId) {
        try {
            DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/user/get");
            OapiV2UserGetRequest req = new OapiV2UserGetRequest();
            req.setUserid(userId);
            String corpAccessToken = getCorpAccessToken(corpId);
            OapiV2UserGetResponse rsp = client.execute(req, corpAccessToken);
            return rsp.getResult();
        } catch (ApiException e) {
            log.error("获取用户详情失败", e);
            throw new ServiceException("获取用户详情失败");
        }
    }

    public static List<OapiV2DepartmentListsubResponse.DeptBaseResponse> getDeptList(String corpId, Long deptId) {
        try {
            DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/department/listsub");
            OapiV2DepartmentListsubRequest req = new OapiV2DepartmentListsubRequest();
            req.setDeptId(deptId);
            req.setLanguage("zh_CN");
            String corpAccessToken = getCorpAccessToken(corpId);
            OapiV2DepartmentListsubResponse rsp = client.execute(req, corpAccessToken);
            return rsp.getResult();
        } catch (Exception e) {
            log.error("获取用户部门失败", e);
            throw new ServiceException("获取用户部门失败");
        }
    }

    private static com.aliyun.dingtalkoauth2_1_0.Client getClient2() throws Exception {
        Config config = new Config();
        config.protocol = "https";
        config.regionId = "central";
        return new com.aliyun.dingtalkoauth2_1_0.Client(config);
    }

}
