package com.jeelowcode.service.system.config.social;

import cn.hutool.core.lang.Assert;
import cn.hutool.http.HttpRequest;
import com.alibaba.fastjson.JSONObject;
import com.jeelowcode.service.system.util.SshUtils;
import com.xingyuv.jushauth.cache.AuthStateCache;
import com.xingyuv.jushauth.config.AuthConfig;
import com.xingyuv.jushauth.config.AuthSource;
import com.xingyuv.jushauth.exception.AuthException;
import com.xingyuv.jushauth.model.AuthCallback;
import com.xingyuv.jushauth.model.AuthToken;
import com.xingyuv.jushauth.model.AuthUser;
import com.xingyuv.jushauth.request.AuthDefaultRequest;
import lombok.extern.slf4j.Slf4j;

/**
 * Description: 中国星网认证
 * Author: JeeLow
 * Date: 2021/11/23 16:05
 */
@Slf4j
public class ChinaSatelliteAuthRequest extends AuthDefaultRequest {

    /**
     * 构造函数
     *
     * @param config 配置
     * @param source 源
     */
    public ChinaSatelliteAuthRequest(AuthConfig config, AuthSource source) {
        super(config, ChinaSatelliteAuthSource.CHINA_SATELLITE_NET);
    }

    /**
     * 构造函数
     *
     * @param config         配置
     * @param authStateCache 缓存
     */
    public ChinaSatelliteAuthRequest(AuthConfig config, AuthStateCache authStateCache) {
        super(config, ChinaSatelliteAuthSource.CHINA_SATELLITE_NET, authStateCache);
    }

    @Override
    protected AuthToken getAccessToken(AuthCallback authCallback) {
        // 1.首先使用授权码获取token
        String responseStr = doPostAuthorizationCode(authCallback.getCode());
        JSONObject responseObj = JSONObject.parseObject(responseStr);

        // 2.检查响应结果是否包含错误信息
        this.checkResponse(responseObj);

        // 3.解析响应结果，获取token信息
        return AuthToken.builder()
                .accessToken(responseObj.getString("access_token"))
                .refreshToken(responseObj.getString("refresh_token"))
                .expireIn(responseObj.getInteger("expires_in"))
                .tokenType(responseObj.getString("token_type"))
                .build();
    }

    @Override
    protected AuthUser getUserInfo(AuthToken authToken) {
        // 1.使用token获取用户信息
        String responseStr = doGetUserInfo(authToken);
        JSONObject responseObj = JSONObject.parseObject(responseStr);

        // 2.检查响应结果是否包含错误信息
        this.checkResponse(responseObj);

        // 3.解析响应结果，获取用户信息
        JSONObject result = responseObj.getJSONObject("result");
        Assert.notNull(result, () -> new AuthException("响应结果 result 不能为空"));
        return AuthUser.builder()
                .uuid(result.getString("id"))
                .nickname(result.getString("displayName"))
                .rawUserInfo(result)
                .token(authToken)
                .build();
    }

    /**
     * 检查响应结果是否包含错误信息
     *
     * @param response 响应结果
     */
    private void checkResponse(JSONObject response) {
        if (response.containsKey("error")) {
            throw new AuthException(response.getString("error"));
        }
    }

    @Override
    protected String doPostAuthorizationCode(String code) {
        try {
            return HttpRequest.post(this.accessTokenUrl(code))
                    .setSSLSocketFactory(SshUtils.createTrustAllSSLFactory())
                    .execute().body();
        } catch (Exception e) {
            log.error("[getAccessToken][code({}) 获取token失败]", code, e);
            throw new AuthException("获取token失败");
        }
    }

    @Override
    protected String doGetUserInfo(AuthToken authToken) {
        try {
            return HttpRequest.get(this.userInfoUrl(authToken))
                    .header("Authorization", authToken.getAccessToken())
                    .setSSLSocketFactory(SshUtils.createTrustAllSSLFactory())
                    .execute().body();
        } catch (Exception e) {
            log.error("[getUserInfo][accessToken({}) 获取用户信息失败]", authToken.getAccessToken(), e);
            throw new AuthException("获取用户信息失败");
        }
    }

}
