package com.codvision.auth.service.third;

import cn.hutool.core.lang.UUID;
import cn.hutool.json.JSONUtil;
import com.alibaba.xxpt.gateway.shared.api.request.*;
import com.alibaba.xxpt.gateway.shared.api.response.*;
import com.alibaba.xxpt.gateway.shared.client.http.ExecutableClient;
import com.alibaba.xxpt.gateway.shared.client.http.IntelligentGetClient;
import com.alibaba.xxpt.gateway.shared.client.http.IntelligentPostClient;
import com.alibaba.xxpt.gateway.shared.client.http.api.OapiSpResultContent;
import com.codvision.auth.entity.ding.DingEnv;
import com.codvision.auth.entity.ding.gov.GovUserInfo;
import com.codvision.auth.entity.ding.gov.msg.DingLinkMsg;
import com.codvision.auth.entity.ding.gov.msg.DingMarkDownMsg;
import com.codvision.auth.entity.ding.gov.msg.DingTextMsg;
import com.codvision.auth.entity.vo.GovResponseVO;
import com.codvision.base.service.ISysConfigService;
import com.codvision.cachecore.utils.RedisUtil;
import com.codvision.commoncore.exception.BusinessException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;

import static com.codvision.auth.support.CacheContants.*;


/**
 * 专有钉钉（浙政钉）服务
 *
 * @author hxl
 */
@Slf4j
@Service
public class GovDingService {

    @Resource
    private ISysConfigService configService;

    private static DingEnv ENV;

    private static ExecutableClient EXECUTABLE_CLIENT;

    @PostConstruct
    public void init() {
        ENV = DingEnv.builder()
                .govDingAppKey(configService.getValueByKey("GOV_DING_APP_KEY")).govDingAppSecret(configService.getValueByKey("GOV_DING_APP_SECRET"))
                .govDingTelnetId(configService.getValueByKey("GOV_DING_TELNET_ID")).govDingCorpId(configService.getValueByKey("GOV_DING_CORP_ID"))
                .govDingApiUrlPrefix(configService.getValueByKey("GOV_DING_API_URL_PREFIX")).govDingScanDomainUrl(configService.getValueByKey("GOV_DING_SCAN_DOMAIN_URL"))
                .govDingScanAppKey(configService.getValueByKey("GOV_DING_SCAN_APP_KEY")).govDingScanAppSecret(configService.getValueByKey("GOV_DING_SCAN_APP_SECRET"))
                .govDingScanRedirectUrl(configService.getValueByKey("GOV_DING_SCAN_REDIRECT_URL")).govDingScanAppFlag(configService.getValueByKey("GOV_DING_SCAN_APP_FLAG"))
                .build();

        EXECUTABLE_CLIENT = ExecutableClient.getInstance();
        EXECUTABLE_CLIENT.setProtocal("https");
        EXECUTABLE_CLIENT.setDomainName(ENV.getGovDingApiUrlPrefix());
        EXECUTABLE_CLIENT.setAccessKey(ENV.getGovDingAppKey());
        EXECUTABLE_CLIENT.setSecretKey(ENV.getGovDingAppSecret());
        EXECUTABLE_CLIENT.init();
    }


    /**
     * 获取access_token
     *
     * @return access_token
     */
    public String getAccessToken() {
        return getAccessToken(ENV.getGovDingAppKey(), ENV.getGovDingAppSecret(), GOV_DING_TOKEN);
    }

    /**
     * 获取access_token（扫码）
     *
     * @return access_token
     */
    public String getScanAccessToken() {
        return getAccessToken(ENV.getGovDingScanAppKey(), ENV.getGovDingScanAppSecret(), GOV_DING_SCAN_TOKEN);
    }

    private String getAccessToken(String appKey, String appSecret, String cacheKey) {
        String accessToken = RedisUtil.get(cacheKey);
        if (StringUtils.isNotBlank(accessToken)) {
            return accessToken;
        }

        IntelligentGetClient intelligentGetClient = EXECUTABLE_CLIENT.newIntelligentGetClient("/gettoken.json");
        OapiGettokenJsonRequest oapiGettokenJsonRequest = new OapiGettokenJsonRequest();
        oapiGettokenJsonRequest.setAppkey(appKey);
        oapiGettokenJsonRequest.setAppsecret(appSecret);
        OapiGettokenJsonResponse rsp = intelligentGetClient.get(oapiGettokenJsonRequest);
        OapiSpResultContent content = rsp.getContent();
        if (!content.getSuccess()) {
            throw new BusinessException(content.getResponseMessage());
        }

        accessToken = (String) JSONUtil.parseObj(content.getData()).get("accessToken");
        // access_token有效期为7200秒，有效期内重复获取返回相同结果并⾃动续期。防止临界过期问题，缓存失效时间比实际过期时间设置的偏低
        RedisUtil.set(GOV_DING_TOKEN, accessToken, 119, TimeUnit.MINUTES);
        return accessToken;
    }

    /**
     * JSAPI鉴权
     *
     * @return 鉴权ticket
     */
    public String getTicket() {
        String ticketAccessToken = RedisUtil.get(GOV_DING_TICKET_TOKEN);
        if (StringUtils.isNotBlank(ticketAccessToken)) {
            return ticketAccessToken;
        }

        IntelligentGetClient intelligentGetClient = EXECUTABLE_CLIENT.newIntelligentGetClient("/get_jsapi_token.json");
        OapiGetJsapiTokenJsonRequest oapiGetJsapiTokenJsonRequest = new OapiGetJsapiTokenJsonRequest();
        oapiGetJsapiTokenJsonRequest.setAccessToken(getAccessToken());
        OapiGetJsapiTokenJsonResponse rsp = intelligentGetClient.get(oapiGetJsapiTokenJsonRequest);
        OapiSpResultContent content = rsp.getContent();
        if (!content.getSuccess()) {
            throw new BusinessException(content.getResponseMessage());
        }

        ticketAccessToken = (String) JSONUtil.parseObj(content.getData()).get("accessToken");
        // JsApi获取access_token，access_token有效期为7200秒，有效期内重复获取返回相同结果，不会自动续期
        RedisUtil.set(GOV_DING_TICKET_TOKEN, ticketAccessToken, 2, TimeUnit.HOURS);
        return ticketAccessToken;
    }

    /**
     * 获取授权用户的个人信息（扫码）
     *
     * @param code 临时授权码
     */
    public GovUserInfo getUserInfoByScan(String code) {
        IntelligentGetClient intelligentGetClient = EXECUTABLE_CLIENT.newIntelligentGetClient("/rpc/oauth2/getuserinfo_bycode.json");
        OapiRpcOauth2GetuserinfoBycodeJsonRequest oapiRpcOauth2GetuserinfoBycodeJsonRequest = new OapiRpcOauth2GetuserinfoBycodeJsonRequest();
        oapiRpcOauth2GetuserinfoBycodeJsonRequest.setCode(code);
        oapiRpcOauth2GetuserinfoBycodeJsonRequest.setAccess_token(getScanAccessToken());
        OapiRpcOauth2GetuserinfoBycodeJsonResponse rsp = intelligentGetClient.get(oapiRpcOauth2GetuserinfoBycodeJsonRequest);
        GovResponseVO response = throwExceptionIfNecessary(rsp.getContent());
        return JSONUtil.toBean(JSONUtil.toJsonStr(response.getData()), GovUserInfo.class);
    }


    /**
     * 获取授权用户的个人信息（免登）
     *
     * @param authCode 临时授权码
     */
    public GovUserInfo getUserInfo(String authCode) {
        IntelligentPostClient intelligentPostClient = EXECUTABLE_CLIENT.newIntelligentPostClient("/rpc/oauth2/dingtalk_app_user.json");
        OapiRpcOauth2DingtalkAppUserJsonRequest oapiRpcOauth2DingtalkAppUserJsonRequest = new OapiRpcOauth2DingtalkAppUserJsonRequest();
        oapiRpcOauth2DingtalkAppUserJsonRequest.setAccess_token(getAccessToken());
        oapiRpcOauth2DingtalkAppUserJsonRequest.setAuth_code(authCode);
        OapiRpcOauth2DingtalkAppUserJsonResponse rsp = intelligentPostClient.post(oapiRpcOauth2DingtalkAppUserJsonRequest);
        GovResponseVO response = throwExceptionIfNecessary(rsp.getContent());
        return JSONUtil.toBean(JSONUtil.toJsonStr(response.getData()), GovUserInfo.class);
    }


    /**
     * 工作通知消息
     *
     * @param receiverIds 接收人用户ID(accountId)
     * @param msg         消息内容 json格式
     */
    public void workNotification(String receiverIds, String msg) {
        IntelligentGetClient intelligentGetClient = EXECUTABLE_CLIENT.newIntelligentGetClient("/message/workNotification");
        OapiMessageWorkNotificationRequest oapiMessageWorkNotificationRequest = new OapiMessageWorkNotificationRequest();
        //接收人用户ID，多个人时使用半角逗号分隔
        oapiMessageWorkNotificationRequest.setReceiverIds(receiverIds);
        oapiMessageWorkNotificationRequest.setTenantId(ENV.getGovDingTelnetId());
        oapiMessageWorkNotificationRequest.setBizMsgId(UUID.fastUUID().toString());
        oapiMessageWorkNotificationRequest.setMsg(msg);
        OapiMessageWorkNotificationResponse rsp = intelligentGetClient.get(oapiMessageWorkNotificationRequest);
        if (StringUtils.isBlank(rsp.getContent())) {
            throw new BusinessException(rsp.getErrorMsg());
        }
    }


    /**
     * 文本消息（工作通知消息）
     *
     * @param receiverIds 接收人用户ID(accountId)
     * @param content     消息内容
     */
    public void sendTextMsg(String receiverIds, String content) {
        workNotification(receiverIds, JSONUtil.toJsonStr(new DingTextMsg(new DingTextMsg.TextMsg(content))));
    }

    /**
     * 链接消息（工作通知消息）
     *
     * @param receiverIds 接收人用户ID(accountId)
     * @param title       消息标题
     * @param text        消息描述
     * @param messageUrl  消息点击链接地址，当发送消息为小程序时支持小程序跳转链接
     * @param picUrl      图片地址
     */
    public void sendLinkMsg(String receiverIds, String title, String text, String messageUrl, String picUrl) {
        workNotification(receiverIds, JSONUtil.toJsonStr(new DingLinkMsg(new DingLinkMsg.LinkMsg(messageUrl, picUrl, title, text))));
    }

    /**
     * MarkDown消息（工作通知消息）
     *
     * @param receiverIds 接收人用户ID(accountId)
     * @param title       标题
     * @param text        markdown的文本
     */
    public void sendMarkDownMsg(String receiverIds, String title, String text) {
        workNotification(receiverIds, JSONUtil.toJsonStr(new DingMarkDownMsg(new DingMarkDownMsg.MarkDownMsg(title, text))));
    }


    private GovResponseVO throwExceptionIfNecessary(String rspContent) {
        GovResponseVO response = JSONUtil.toBean(JSONUtil.toJsonStr(rspContent), GovResponseVO.class);
        if (!response.getSuccess()) {
            throw new BusinessException(response.getResponseMessage());
        }

        return response;
    }
}
