package com.malk.service.dingtalk.impl;

import com.malk.server.dingtalk.DDConf;
import com.malk.server.dingtalk.DDR;
import com.malk.server.dingtalk.DDR_New;
import com.malk.service.dingtalk.DDClient;
import com.malk.utils.UtilHttp;
import com.malk.utils.UtilMap;
import com.malk.utils.UtilToken;
import lombok.Synchronized;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;

@Slf4j
@Service
public class DDImplClient implements DDClient {

    @Autowired
    private DDConf ddConf;

    /**
     * 获取访问授权
     *
     * @apiNote https://open.dingtalk.com/document/personalapp-service/obtain-user-token
     */
    @Synchronized
    @Override
    public String getAccessToken() {
        String accessToken = UtilToken.get("invalid-token-dingtalk");
        if (StringUtils.isNotBlank(accessToken)) return accessToken;
        Map param = new HashMap();
        param.put("appkey", ddConf.getAppKey());
        param.put("appsecret", ddConf.getAppSecret());
        DDR r = (DDR) UtilHttp.doGet("https://oapi.dingtalk.com/gettoken", param, DDR.class);
        log.info("响应token, {}", r.getAccessToken());
        accessToken = r.getAccessToken();
        // token失效自动重置: DD重新调用会重置过期时间
        UtilToken.put("invalid-token-dingtalk", accessToken, r.getExpiresIn() * 1000L);
        return accessToken;
    }


    @Override
    public String getAccessToken(String appKey, String appSecret) {
        Map param = UtilMap.map("appkey, appsecret", appKey, appSecret);
        DDR r = DDR.doGet("https://oapi.dingtalk.com/gettoken", null, param);
        log.info("响应token, {}", r.getAccessToken());
        return r.getAccessToken();
    }

    /**
     * 获取用户访问授权, ppExt: 生成的refresh_token。可以使用此刷新token，定期的获取用户的accessToken: 过期时间 30 天
     *
     * @apiNote https://open.dingtalk.com/document/orgapp/obtain-user-token
     */
    @Synchronized
    @Override
    public String getUserAccessToken(boolean isRefresh, String code_refreshToken) {
        String accessToken = UtilToken.get("invalid-user-token-dingtalk");
        if (StringUtils.isNotBlank(accessToken)) return accessToken;
        Map boyd = UtilMap.map("clientId, clientSecret", ddConf.getAppKey(), ddConf.getAppSecret());
        if (isRefresh) {
            boyd.put("grantType", "refresh_token");
            boyd.put("refreshToken", code_refreshToken);
        } else {
            boyd.put("grantType", "authorization_code");
            boyd.put("code", code_refreshToken);
        }
        DDR_New r = (DDR_New) UtilHttp.doPost("https://api.dingtalk.com/v1.0/oauth2/userAccessToken", null, boyd, DDR_New.class);
        log.info("用户token, {}", r.getAccessToken());
        accessToken = r.getAccessToken();
        // token失效自动重置: DD重新调用会重置过期时间
        UtilToken.put("invalid-user-token-dingtalk", accessToken, r.getExpiresIn() * 1000L);
        return accessToken;
    }

    /**
     * token授权参数: 旧版本
     */
    @Override
    public Map initTokenParams() {
        return DDConf.initTokenParams(getAccessToken());
    }

    /**
     * token授权参数: 新版本
     */
    @Override
    public Map initTokenHeader() {
        return DDConf.initTokenHeader(getAccessToken());
    }

    /**
     * 获取jsapi_ticket
     *
     * @apiNote https://open.dingtalk.com/document/orgapp/obtain-jsapi_ticket
     */
    @Synchronized
    @Override
    public String getJsApiTicket(String accessToken) {
        String ticket = UtilToken.get("invalid-ticket-dingtalk");
        if (StringUtils.isNotBlank(ticket)) return ticket;
        DDR r = DDR.doGet("https://oapi.dingtalk.com/get_jsapi_ticket", null, UtilMap.map("access_token", accessToken));
        log.info("响应ticket, {}", r.getAccessToken());
        ticket = r.getTicket();
        // token失效自动重置: DD重新调用会重置过期时间
        UtilToken.put("invalid-ticket-dingtalk", ticket, r.getExpiresIn() * 1000L);
        return ticket;
    }

    /**
     * 通过免登码获取用户信息
     */
    @Override
    public Map getUserInfoByCode(String accessToken, String code) {
        return (Map) DDR.doPost("https://oapi.dingtalk.com/topapi/v2/user/getuserinfo", null, DDConf.initTokenParams(accessToken), UtilMap.map("code", code)).getResult();
    }
}