package com.qy.sso.bamboocloud.validation;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.kingdee.bos.Context;
import com.kingdee.eas.cp.eip.sso.util.CASLoginConfigPropUtil;
import com.kingdee.eas.cp.eip.sso.util.CloudParamUtil;
import com.kingdee.eas.util.app.DbUtil;
import com.kingdee.jdbc.rowset.IRowSet;
import com.kingdee.util.StringUtils;
import okhttp3.*;
import org.jasig.cas.client.authentication.AttributePrincipal;
import org.jasig.cas.client.authentication.AttributePrincipalImpl;
import org.jasig.cas.client.ssl.HttpURLConnectionFactory;
import org.jasig.cas.client.ssl.HttpsURLConnectionFactory;
import org.jasig.cas.client.validation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * @Description 竹云系统单点身份校验器
 * @Date 2024/9/23 19:28
 * @Created by Heyuan
 */
public class ZYPortalServiceTicketValidator implements TicketValidator {
    //org.jasig.cas.client.validation.Cas20ServiceTicketValidator
    protected final Logger logger = LoggerFactory.getLogger(this.getClass());
    //httpurl链接工厂
    private HttpURLConnectionFactory urlConnectionFactory = new HttpsURLConnectionFactory();
    //private final String casServerUrlPrefix;
    private boolean renew;
    private Map<String, String> customParameters;
    private String encoding;
    private String clientSecret;
    private String grantType;
    private String clientId;
    private String responseType;
    private String getTokenPath;//获取授权接口,相对地址
    private String getUserInfoPath;//获取用户信息接口,相对地址


    /**
     * 校验
     * 不能返回空对象并且assertion.getPrincipal()也不能为空!
     *
     * @param code    身份标识
     * @param service
     * @return
     * @throws TicketValidationException
     */
    public final Assertion validate(String code,
                                    String service) throws TicketValidationException {
        //String validationUrl = this.constructValidationUrl(code, service);
        //this.logger.debug("Constructing validation url: {}", validationUrl);
        HashMap attributes = new HashMap<>();
        try {
            this.logger.debug("Retrieving response from server.");
            Map<String, Object> token = getToken(code, null);
            String loginName = getUserInfo(token);//员工编码
            this.logger.debug("获取员工信息 登录账号: " + loginName);
            if (StringUtils.isEmpty(loginName)) {
                throw new TicketValidationException("获取用户信息的登录账号为空!");
            }
            String dataCenter = CASLoginConfigPropUtil.getDataCenter();
            String locale = CASLoginConfigPropUtil.getLocale();
            if (!StringUtils.isEmpty(dataCenter) && !StringUtils.isEmpty(locale)) {
                Context ctx = CloudParamUtil.getContext(dataCenter, locale, "administrator");
                String sql = "SELECT fnumber FROM T_PM_USER WHERE LOWER(CFZYLoginName)=?";
                IRowSet rs = DbUtil.executeQuery(ctx, sql, new Object[]{loginName.toLowerCase()});
                String userNumber = null;
                if (rs.next()) {
                    userNumber = rs.getString("fnumber");
                }
                if (StringUtils.isEmpty(userNumber)) {
                    this.logger.error("loginName :" + loginName + "不是shr用户");
                    attributes.put("isFail", true);
                    userNumber = loginName;
                    //throw new TicketValidationException("loginName :" + loginName + "不是shr用户");
                }
                //创建登录用户
                AttributePrincipal principal = new AttributePrincipalImpl(userNumber);
                return new AssertionImpl(principal, attributes);
            } else {
                throw new TicketValidationException("数据中心 或 locale 为空!");
            }
        } catch (Exception var5) {
            var5.printStackTrace();
            throw new TicketValidationException(var5);
        }
    }

    /**
     * 获取token
     *
     * @param code
     * @param state
     * @return
     * @throws TicketValidationException
     */
    private Map<String, Object> getToken(String code, String state) throws TicketValidationException {
        this.logger.debug("code: " + code);
        this.logger.debug("state: " + state);
        if (StringUtils.isEmpty(code)) {
            //检查session
            throw new TicketValidationException("code 不能为空!");
        }
        OkHttpClient client = new OkHttpClient();
        MediaType mediaType = MediaType.parse("application/x-www-form-urlencoded");
        Map<String, String> params = new HashMap<>();
        params.put("client_id", this.clientId);
        params.put("client_secret", this.clientSecret);
        params.put("code", code);
        params.put("grant_type", this.grantType);
        RequestBody body = RequestBody.create(mediaType, constructRequestParameter(params));
        Request request = new Request.Builder()
                .url(this.getTokenPath)
                .post(body)
                .addHeader("content-type", "application/x-www-form-urlencoded")
                .build();
        Response sYResponse = null;
        try {
            sYResponse = client.newCall(request).execute();
        } catch (IOException e) {
            e.printStackTrace();
            throw new TicketValidationException("获取Token请求执行失败!");
        }
        if (sYResponse.isSuccessful()) {
            try {
                String result = sYResponse.body().string();
                this.logger.debug("getToken sYResponse : " + result);
                ObjectMapper objectMapper = new ObjectMapper();
                Map<String, Object> map = objectMapper.readValue(result, Map.class);
                String errcode = (String) map.get("errcode");
                if (StringUtils.isEmpty(errcode)) {
                    //请求成功
                    return map;
                } else {
                    String msg = (String) map.get("msg");//错误信息
                    throw new TicketValidationException("获取Token失败: " + msg);
                }
            } catch (IOException e) {
                e.printStackTrace();
                throw new TicketValidationException("获取Token失败: " + e.getMessage());
            }
        } else {
            //失败
            throw new TicketValidationException("获取Token请求失败");
        }
    }

    /**
     * 获取用户信息
     *
     * @param tokenResponse
     * @return
     * @throws TicketValidationException
     */
    private String getUserInfo(Map<String, Object> tokenResponse) throws TicketValidationException {
        if (tokenResponse == null) {
            throw new TicketValidationException("tokenResponse 不能为空!");
        }
        String access_token = (String) tokenResponse.get("access_token");
//        int expires_in = tokenResponse.getInteger("expires_in");
//        String refresh_token = tokenResponse.getString("refresh_token");
//        String uid = tokenResponse.getString("uid");//登录用户
        OkHttpClient client = new OkHttpClient();
        Map<String, String> params = new HashMap<>();
        params.put("client_id", this.clientId);
        params.put("access_token", access_token);
        Request request = new Request.Builder()
                .url(this.getUserInfoPath + "?" + constructRequestParameter(params))
                .get()
                .addHeader("content-type", "application/json")
                .build();
        Response sYResponse = null;
        try {
            sYResponse = client.newCall(request).execute();
        } catch (IOException e) {
            e.printStackTrace();
            throw new TicketValidationException("获取用户信息请求执行失败!");
        }
        if (sYResponse.isSuccessful()) {
            try {
                String result = sYResponse.body().string();
                this.logger.debug("getUserInfo sYResponse : " + result);
                ObjectMapper objectMapper = new ObjectMapper();
                Map<String, Object> map = objectMapper.readValue(result, Map.class);
                String errcode = (String) map.get("errcode");
                if (StringUtils.isEmpty(errcode)) {
                    //请求成功
                    return (String) map.get("loginName");//登录账号
                } else {
                    String msg = (String) map.get("msg");//错误信息
                    throw new TicketValidationException("获取用户信息失败: " + msg);
                }
            } catch (IOException e) {
                e.printStackTrace();
                throw new TicketValidationException("获取用户信息失败: " + e.getMessage());
            }
        } else {
            //失败
            throw new TicketValidationException("获取用户信息请求失败 ");
        }
    }

    /**
     * 构建请求参数
     *
     * @param map
     * @return
     */
    private String constructRequestParameter(Map<String, String> map) {
        StringBuilder parameters = new StringBuilder();
        if (map != null) {
            for (String key : map.keySet()) {
                String value = map.get(key);
                parameters.append(key).append("=").append(value).append("&");
            }
            parameters.deleteCharAt(parameters.lastIndexOf("&"));
        }
        return parameters.toString();
    }

    protected String getUrlSuffix() {
        return "serviceValidate";
    }

    public HttpURLConnectionFactory getUrlConnectionFactory() {
        return urlConnectionFactory;
    }

    public void setUrlConnectionFactory(HttpURLConnectionFactory urlConnectionFactory) {
        this.urlConnectionFactory = urlConnectionFactory;
    }

    public boolean isRenew() {
        return renew;
    }

    public void setRenew(boolean renew) {
        this.renew = renew;
    }

    public Map<String, String> getCustomParameters() {
        return customParameters;
    }

    public void setCustomParameters(Map<String, String> customParameters) {
        this.customParameters = customParameters;
    }

    public String getEncoding() {
        return encoding;
    }

    public void setEncoding(String encoding) {
        this.encoding = encoding;
    }

    public String getClientSecret() {
        return clientSecret;
    }

    public void setClientSecret(String clientSecret) {
        this.clientSecret = clientSecret;
    }

    public String getGrantType() {
        return grantType;
    }

    public void setGrantType(String grantType) {
        this.grantType = grantType;
    }

    public String getClientId() {
        return clientId;
    }

    public void setClientId(String clientId) {
        this.clientId = clientId;
    }

    public String getResponseType() {
        return responseType;
    }

    public void setResponseType(String responseType) {
        this.responseType = responseType;
    }

    public String getGetTokenPath() {
        return getTokenPath;
    }

    public void setGetTokenPath(String getTokenPath) {
        this.getTokenPath = getTokenPath;
    }

    public String getGetUserInfoPath() {
        return getUserInfoPath;
    }

    public void setGetUserInfoPath(String getUserInfoPath) {
        this.getUserInfoPath = getUserInfoPath;
    }

}
