package com.codvision.auth.support;


import cn.hutool.http.HttpRequest;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.codvision.auth.entity.ding.DingConfig;
import com.codvision.auth.entity.ding.DingEnv;
import com.codvision.base.service.ISysConfigService;
import com.dingtalk.api.DefaultDingTalkClient;
import com.dingtalk.api.DingTalkClient;
import com.dingtalk.api.request.OapiV2DepartmentListsubRequest;
import com.dingtalk.api.request.OapiV2UserListRequest;
import com.dingtalk.api.response.OapiV2DepartmentListsubResponse;
import com.dingtalk.api.response.OapiV2UserListResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.Formatter;
import java.util.UUID;

/**
 * @author codvision
 * @version V1.0
 * @Package com.codvision.serverboot.util
 * @date 2020/3/4 9:56
 * @Copyright © 2012-2021杭州码全科技有限公司
 */
@Component
@Slf4j
public class DingHelper {
    /**
     * 获取access_token的接口地址,有效期为7200秒
     */
    private static final String GET_ACCESS_TOKEN_URL = "https://oapi.dingtalk.com/gettoken?appkey=APPKEY&appsecret=APPSECRET";
    /**
     * 获取getJsapiTicket的接口地址,有效期为7200秒
     */
    private static final String GET_JSAPI_TICKET_URL = "https://oapi.dingtalk.com/get_jsapi_ticket?access_token=ACCESS_TOKEN";
    /**
     * 获取userinfo的URL
     */
    private static final String GET_USER_INFO_URL = "https://oapi.dingtalk.com/user/getuserinfo?access_token=ACCESS_TOKEN&code=CODE";
    /**
     * 获取部门url
     */
    private static final String GET_DEPARTMENT_URL = "https://oapi.dingtalk.com/department/get?access_token=%s&id=%d";
    /**
     * 获取所有部门url
     */
    private static final String GET_DEPARTMENT_LIST_URL = "https://oapi.dingtalk.com/department/list?access_token=ACCESS_TOKEN";
    /**
     * 获取用户详细信息url
     */
    private static final String GET_USER_DETAIL_URL = "https://oapi.dingtalk.com/user/get?access_token=ACCESS_TOKEN&userid=USERID";
    /**
     * 发送工作通知url
     */
    private static final String SEND_MESSAGE_URL = "https://oapi.dingtalk.com/topapi/message/corpconversation/asyncsend_v2?access_token=ACCESS_TOKEN";
    /**
     * 根据手机号获取useridurl
     */
    private static final String GET_USER_ID_URL = "https://oapi.dingtalk.com/user/get_by_mobile?access_token=ACCESS_TOKEN&mobile=MOBILE";

    /**
     * access_token
     */
    public static String DING_ACCESS_TOKEN;
    /**
     * Jsticket
     */
    public static String DING_JSAPI_TICKET;

    /**
     * access_token获取时间
     */
    private static long TOKEN_CACHE_TIME = 0;
    /**
     * Jsticket获取时间
     */
    private static long TICKET_CACHE_TIME = 0;

    @Resource
    private ISysConfigService configService;

    private final DingEnv dingEnv = new DingEnv();

    @PostConstruct
    public DingEnv createDingEnv() {
        dingEnv.setDingAppKey(configService.getValueByKey("DING_APP_KEY"));
        dingEnv.setDingAppSecret(configService.getValueByKey("DING_APP_SECRET"));
        dingEnv.setDingAgentId(configService.getValueByKey("DING_AGENT_ID"));
        dingEnv.setDingCorpId(configService.getValueByKey("DING_CORP_ID"));
        log.info("createDingEnv:" + dingEnv);
        return dingEnv;
    }

    //获取accesstoken
    public synchronized String getAccessToken() {
        long ts = System.currentTimeMillis();
        if (ts - TOKEN_CACHE_TIME > 6400000) {
            System.out.print("Refresh Access token.....");
            try {
                String url = GET_ACCESS_TOKEN_URL.replace("APPKEY", dingEnv.getDingAppKey()).replace("APPSECRET", dingEnv.getDingAppSecret());

                //2.发起GET请求，获取返回结果
                String body = HttpRequest.get(url).execute().body();
                JSONObject jsonObject = JSONUtil.parseObj(body);
                if (null == jsonObject) {
                    return null;
                }
                //3.解析结果，获取accessToken
                DING_ACCESS_TOKEN = jsonObject.getStr("access_token");

                TOKEN_CACHE_TIME = ts;
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }

        return DING_ACCESS_TOKEN;
    }

    /**
     * 2、获取JSTicket, 用于js的签名计算
     * 正常的情况下，jsapi_ticket的有效期为7200秒，所以开发者需要在某个地方设计一个定时器，定期去更新jsapi_ticket
     *
     * @throws Exception
     */
    private synchronized String getJsapiTicket() {

        long ts = System.currentTimeMillis();
        if (ts - TICKET_CACHE_TIME > 6400000) {
            System.out.print("Refresh Access token.....");
            String token = getAccessToken();
            if (null == token) {
                return null;
            }
            try {
                String url = GET_JSAPI_TICKET_URL.replace("ACCESS_TOKEN", token);
                //2.发起GET请求，获取返回结果
                String body = HttpRequest.get(url).execute().body();
                JSONObject jsonObject = JSONUtil.parseObj(body);
                if (null == jsonObject) {
                    return null;
                }
                DING_JSAPI_TICKET = jsonObject.getStr("ticket");
                TICKET_CACHE_TIME = ts;
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
        return DING_JSAPI_TICKET;
    }


    public DingConfig getConfig(String url) {
        //配置类
        DingConfig config = new DingConfig();
        //url
        config.url = url;
        //jsticket
        config.jsticket = getJsapiTicket();
        //noncestr 签名字符串
        config.nonceStr = UUID.randomUUID().toString();
        //timestamp
        config.timeStamp = System.currentTimeMillis() / 1000;
        //corpid
        config.corpId = dingEnv.getDingCorpId();
        //appkey
        config.appkey = dingEnv.getDingAppKey();
        //agentid 企业应用ID
        config.agentId = dingEnv.getDingAgentId();
        try {
            //signature 签名
            config.signature = getSign(config.jsticket, config.nonceStr, config.timeStamp, config.url);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return config;
    }

    public JSONObject getDepartmentList(long parentDeptId) throws Exception {
        DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/department/listsub");
        OapiV2DepartmentListsubRequest req = new OapiV2DepartmentListsubRequest();
            req.setDeptId(parentDeptId);
        req.setLanguage("zh_CN");
        OapiV2DepartmentListsubResponse rsp = client.execute(req, getAccessToken());
        return JSONUtil.parseObj(rsp.getBody());
    }

    public JSONObject getDepartmentUserList(long deptId, long cursor) throws Exception {
        DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/user/list");
        OapiV2UserListRequest req = new OapiV2UserListRequest();
        req.setDeptId(deptId);
        req.setCursor(cursor);
        req.setSize(100L);
        req.setOrderField("modify_desc");
        req.setContainAccessLimit(false);
        req.setLanguage("zh_CN");
        OapiV2UserListResponse rsp = client.execute(req, getAccessToken());
        return JSONUtil.parseObj(rsp.getBody());
    }


    public JSONObject getUserInfo(String code) throws Exception {
        String accessToken = getAccessToken();
        System.out.println("accessToken:" + accessToken);
        String url = GET_USER_INFO_URL.replace("ACCESS_TOKEN", accessToken).replace("CODE", code);
        System.out.println("url:" + url);
        String body = HttpRequest.get(url).execute().body();
        JSONObject jsonObject = JSONUtil.parseObj(body);
        System.out.println("jsonObject:" + jsonObject);
        if (null != jsonObject) {
            String userid = jsonObject.getStr("userid");
            System.out.println("userid:" + userid);
            url = GET_USER_DETAIL_URL.replace("ACCESS_TOKEN", accessToken).replace("USERID", userid);
            String detailBody = HttpRequest.get(url).execute().body();
            JSONObject detail = JSONUtil.parseObj(detailBody);
            System.out.println("detail:" + detail);
            return detail;
        }
        return null;
    }

    public static String getDepartment(String accessToken, int departmentId) throws Exception {
        String url = String.format(GET_DEPARTMENT_URL, accessToken, departmentId);
        String body = HttpRequest.get(url).execute().body();
        JSONObject jsonObject = JSONUtil.parseObj(body);
        if (null == jsonObject) {
            jsonObject = new JSONObject();
        }
        return jsonObject.toString();
    }


    /**
     * @param jsTicket  jsticket
     * @param nonceStr  随机串，自己定义
     * @param timeStamp 生成签名用的时间戳
     * @param url       需要进行免登鉴权的页面地址，也就是执行dd.config的页面地址
     * @return
     * @throws Exception String
     * @desc ： 3.生成签名的函数
     */

    public static String getSign(String jsTicket, String nonceStr, Long timeStamp, String url) throws Exception {
        String plainTex = "jsapi_ticket=" + jsTicket + "&noncestr=" + nonceStr + "&timestamp=" + timeStamp + "&url=" + url;
        System.out.println(plainTex);
        MessageDigest crypt = MessageDigest.getInstance("SHA-1");
        crypt.reset();
        crypt.update(plainTex.getBytes(StandardCharsets.UTF_8));
        return byteToHex(crypt.digest());
    }

    //将bytes类型的数据转化为16进制类型
    private static String byteToHex(byte[] hash) {
        Formatter formatter = new Formatter();
        for (byte b : hash) {
            formatter.format("%02x", Byte.valueOf(b));
        }
        String result = formatter.toString();
        formatter.close();
        return result;
    }

}

