package com.usoftchina.dingtalk.sdk;

import com.alibaba.fastjson.JSON;
import com.dingtalk.api.DefaultDingTalkClient;
import com.dingtalk.api.DingTalkClient;
import com.dingtalk.api.request.OapiGettokenRequest;
import com.dingtalk.api.response.OapiGettokenResponse;
import com.taobao.api.ApiException;
import com.taobao.api.TaobaoResponse;
import com.usoftchina.dingtalk.sdk.config.Agent;
import com.usoftchina.dingtalk.sdk.config.DingTalkProperties;
import com.usoftchina.dingtalk.sdk.exception.DingTalkInvokeException;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Callable;

/**
 * @author yingp
 * @date 2020/2/19
 */
public abstract class BaseSdk {
    /**
     * <私钥, Token>
     */
    private final Map<String, AccessToken> accessTokenMap = new HashMap<>();

    private DingTalkProperties properties;

    public BaseSdk(DingTalkProperties properties) {
        this.properties = properties;
    }

    public String getCorpId() {
        return properties.getCorpId();
    }

    protected Map<String, Agent> getAgentMap() {
        return properties.getAgentMap();
    }

    protected void assertOK(TaobaoResponse resp) {
        if (!"0".equals(resp.getErrorCode()) && !"40103".equals(resp.getErrorCode())) {
            throw new DingTalkInvokeException(resp);
        }
    }

    protected <R> R cached(Callable<R> callable) {
        try {
            return callable.call();
        } catch (ApiException e) {
            throw new DingTalkInvokeException(e);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * @param agentCode
     * @return
     */
    protected synchronized String getAccessToken(String agentCode) {
        Agent agent = getAgentMap().get(agentCode);
        if (null == agent) {
            throw new RuntimeException("没有找到应用" + agentCode);
        }
        if (!accessTokenMap.containsKey(agent.getAppSecret()) || accessTokenMap.get(agent.getAppSecret()).expired()) {
            DefaultDingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/gettoken");
            OapiGettokenRequest request = new OapiGettokenRequest();
            request.setAppkey(agent.getAppKey());
            request.setAppsecret(agent.getAppSecret());
            request.setHttpMethod("GET");
            OapiGettokenResponse resp = cached(() -> client.execute(request));
            assertOK(resp);
            accessTokenMap.put(agent.getAppSecret(), new AccessToken(resp));
        }
        return accessTokenMap.get(agent.getAppSecret()).getToken();
    }

    class AccessToken {
        private final String token;
        private final long endTime;

        public AccessToken(OapiGettokenResponse resp) {
            this.token = resp.getAccessToken();
            this.endTime = System.currentTimeMillis() + resp.getExpiresIn() * 1000 - 5000;
        }

        public boolean expired() {
            return System.currentTimeMillis() > endTime;
        }

        public String getToken() {
            return token;
        }
    }
}
