package com.kingdee.eas.custom.sso;

import com.alibaba.fastjson.JSONObject;
import com.kingdee.bos.BOSException;
import com.kingdee.bos.BOSObjectFactory;
import com.kingdee.bos.Context;
import com.kingdee.bos.IBOSObject;
import com.kingdee.bos.dao.ormapping.ObjectUuidPK;
import com.kingdee.bos.util.BOSObjectType;
import com.kingdee.bos.util.BOSUuid;
import com.kingdee.eas.common.EASBizException;
import com.kingdee.eas.cp.eip.sso.ltpa.LtpaTokenManager;
import com.kingdee.eas.cp.eip.sso.util.CASLoginConfigPropUtil;
import com.kingdee.eas.cp.eip.sso.util.CloudParamUtil;
import com.kingdee.eas.framework.ICoreBillBase;
import com.kingdee.eas.util.app.DbUtil;
import com.kingdee.jdbc.rowset.IRowSet;
import com.kingdee.util.StringUtils;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import org.apache.log4j.Logger;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;

/**
 * @Description TODO
 * @Date 2024/11/25 10:02
 * @Created by Heyuan
 */
public class SsoUtil {
    private static Logger logger = Logger.getLogger(SsoUtil.class);

    /**
     * 校验流程生效状态
     *
     * @param redirect
     * @param serverName
     * @return
     * @throws BOSException
     * @throws SQLException
     */
    public static String checkFlowEffectiveStateForPc(String redirect, String serverName) throws BOSException, SQLException {
        if (StringUtils.isEmpty(redirect)) {
            throw new RuntimeException("重定向地址不能为空!");
        }
        if (StringUtils.isEmpty(serverName)) {
            throw new RuntimeException("serverName不能为空!");
        }
        int index = redirect.indexOf("?");
        Map<String, String> params = new HashMap<>();
        if (index > 0) {
            String redirectParams = redirect.substring(index + 1);
            String[] arrary = redirectParams.split("&");
            for (int i = 0; i < arrary.length; i++) {
                String[] split = arrary[i].split("=");
                params.put(split[0], split[1]);
            }
        } else {
            return redirect;
        }
        //流程id
        String assignmentId = params.get("AssignmentId");
        if (StringUtils.isEmpty(assignmentId)) {
            assignmentId = params.get("assignId");
        }
        if (StringUtils.isEmpty(assignmentId)) {
            return redirect;
        }
        String dataCenter = CASLoginConfigPropUtil.getDataCenter();
        String locale = CASLoginConfigPropUtil.getLocale();
        if (!StringUtils.isEmpty(dataCenter) && !StringUtils.isEmpty(locale)) {
            //todo
            Context ctx = CloudParamUtil.getContext(dataCenter, locale, "administrator");
            String sql = "SELECT count(1) total FROM T_WFR_Assign WHERE FASSIGNID = ?";
            IRowSet rs = DbUtil.executeQuery(ctx, sql, new Object[]{assignmentId});
            int total = 0;
            while (rs.next()) {
                total = rs.getInt("total");
            }
            if (total <= 0) {
                return serverName + "/shr/flowErrorPage.jsp";
            } else {
                return redirect;
            }
        }
        logger.error("获取用户信息报错,数据中心没找到!");
        throw new RuntimeException("获取用户信息报错,数据中心没找到!");
    }

    /**
     * 移动端校验流程生效状态
     *
     * @param redirect
     * @param serverName
     * @param getLoginIdPath
     * @param token
     * @return
     * @throws SQLException
     * @throws BOSException
     * @throws IOException
     */
    public static String checkFlowEffectiveStateForMbos(String redirect,
                                                        String serverName,
                                                        String getLoginIdPath,
                                                        String token) throws SQLException, BOSException, IOException {
        if (StringUtils.isEmpty(getLoginIdPath)) {
            throw new RuntimeException("getLoginIdPath不能为空!");
        }
        if (StringUtils.isEmpty(serverName)) {
            throw new RuntimeException("serverName不能为空!");
        }
        if (StringUtils.isEmpty(token)) {
            throw new RuntimeException("token不能为空!");
        }
        redirect = checkFlowEffectiveStateForPc(redirect, serverName);
        if (redirect.contains("/shr/flowErrorPage.jsp")) {
            String userNumber = SsoUtil.loginId2userId(getLoginIdPath, token);
            String password = LtpaTokenManager.generate(userNumber, LtpaTokenManager.getDefaultLtpaConfig()).toString();
            logger.error("login: password" + password);
            StringBuilder url = new StringBuilder();
            url.append(serverName).append("/shr/index2sso.jsp?username=").append(userNumber)
                    .append("&password=").append(password).append("&redirectTo=");
            String encode = URLEncoder.encode(redirect, "UTF-8");
            url.append(URLEncoder.encode(encode, "UTF-8"));
            return url.toString();
        } else {
            return redirect;
        }
    }


    /**
     * 校验单据是否存在
     *
     * @param redirect
     * @param serverName
     * @return
     * @throws BOSException
     * @throws SQLException
     */
    public static String checkBillExistForPc(String redirect,
                                             String serverName)
            throws BOSException, SQLException, EASBizException, UnsupportedEncodingException {
        if (StringUtils.isEmpty(redirect)) {
            throw new RuntimeException("重定向地址不能为空!");
        }
        if (StringUtils.isEmpty(serverName)) {
            throw new RuntimeException("serverName不能为空!");
        }
        int index = redirect.indexOf("?");
        Map<String, String> params = new HashMap<>();
        if (index > 0) {
            String redirectParams = redirect.substring(index + 1);
            String[] arrary = redirectParams.split("&");
            for (int i = 0; i < arrary.length; i++) {
                String[] split = arrary[i].split("=");
                if (split.length > 1) {
                    params.put(split[0], split[1]);
                }
            }
        } else {
            return redirect;
        }
        //流程id
        String assignmentId = params.get("AssignmentId");
        if (StringUtils.isEmpty(assignmentId)) {
            assignmentId = params.get("assignId");
        }
        if (StringUtils.isEmpty(assignmentId)) {
            assignmentId = params.get("assignmentId");
        }
        String billID = params.get("billID");
        if (StringUtils.isEmpty(assignmentId) || StringUtils.isEmpty(billID)) {
            return redirect;
        }
        String dataCenter = CASLoginConfigPropUtil.getDataCenter();
        String locale = CASLoginConfigPropUtil.getLocale();
        if (!StringUtils.isEmpty(dataCenter) && !StringUtils.isEmpty(locale)) {
            Context ctx = CloudParamUtil.getContext(dataCenter, locale, "administrator");
            //todo
            billID = URLDecoder.decode(billID, "UTF-8");
            String bosType = BOSUuid.read(billID).getType().toString();
            ICoreBillBase bosObject = (ICoreBillBase) BOSObjectFactory.createBOSObject(ctx, new BOSObjectType(bosType));
            if (bosObject.exists(new ObjectUuidPK(billID))) {
                return redirect;
            } else {
                return serverName + "/shr/flowErrorPage.jsp";
            }
        }
        logger.error("获取用户信息报错,数据中心没找到!");
        throw new RuntimeException("获取用户信息报错,数据中心没找到!");
    }

    /**
     * 校验流程生效状态
     *
     * @param redirect
     * @param serverName
     * @return
     * @throws BOSException
     * @throws SQLException
     */
    public static String checkBillExistForMbos(String redirect,
                                               String serverName,
                                               String getLoginIdPath,
                                               String token)
            throws BOSException, SQLException, EASBizException, IOException {
        if (StringUtils.isEmpty(getLoginIdPath)) {
            throw new RuntimeException("getLoginIdPath不能为空!");
        }
        if (StringUtils.isEmpty(serverName)) {
            throw new RuntimeException("serverName不能为空!");
        }
        if (StringUtils.isEmpty(token)) {
            throw new RuntimeException("token不能为空!");
        }
        redirect = checkBillExistForPc(redirect, serverName);
        if (redirect.contains("/shr/flowErrorPage.jsp")) {
            String userNumber = SsoUtil.loginId2userId(getLoginIdPath, token);
            String password = LtpaTokenManager.generate(userNumber, LtpaTokenManager.getDefaultLtpaConfig()).toString();
            logger.error("login: password" + password);
            StringBuilder url = new StringBuilder();
            url.append(serverName).append("/shr/index2sso.jsp?username=").append(userNumber)
                    .append("&password=").append(password).append("&redirectTo=");
            String encode = URLEncoder.encode(redirect, "UTF-8");
            url.append(URLEncoder.encode(encode, "UTF-8"));
            return url.toString();
        } else {
            return redirect;
        }
    }


    /**
     * 获取用户信息
     *
     * @param accessToken
     * @return
     * @throws IOException
     * @throws BOSException
     * @throws SQLException
     */
    public static String loginId2userId(String getLoginIdPath, String accessToken)
            throws IOException, BOSException, SQLException {
        if (StringUtils.isEmpty(accessToken)) {
            throw new RuntimeException("accessToken不能为空! ");
        }
        //获取第三方用户信息
        Map params = new HashMap();
        params.put("access_token", accessToken);
        String url = appendUrl(getLoginIdPath, params);
        logger.error("loginId2userId url" + url);
        OkHttpClient client = new OkHttpClient();
        Request request = new Request.Builder()
                .url(url)
                .get()
                .addHeader("content-type", "multipart/form-data; boundary=---011000010111000001101001")
                .build();
        Response response = client.newCall(request).execute();
        if (response.isSuccessful()) {
            String string = response.body().string();
            JSONObject jsonObject = JSONObject.parseObject(string);
            String code = jsonObject.getString("code");
            if ("0".equals(code)) {
                JSONObject attributes = jsonObject.getJSONObject("attributes");
                //登录id
                String loginid = attributes.getString("loginid");
                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 count(1) total FROM T_PM_USER WHERE fnumber=?";
                    IRowSet rs = DbUtil.executeQuery(ctx, sql, new Object[]{loginid});
                    int total = 0;
                    if (rs.next()) {
                        total = rs.getInt("total");
                    }
                    if (total <= 0) {
                        logger.error("SHR找不到对应的用户, loginid:" + loginid);
                        throw new RuntimeException("SHR找不到对应的用户, loginid: " + loginid);
                        //("您无权限访问SHR系统，请联系管理员处理。")
                    } else if (total > 1) {
                        logger.error("SHR找到多个对应的用户, loginid:" + loginid);
                        throw new RuntimeException("SHR找到多个对应的用户, loginid: " + loginid);
                        //("您无权限访问SHR系统，请联系管理员处理。")
                    } else {
                        return loginid;
                    }
                }
                logger.error("获取用户信息报错,数据中心没找到!");
                throw new RuntimeException("获取用户信息报错,数据中心没找到!");
            } else {
                logger.error(jsonObject.getString("msg"));
                throw new RuntimeException(jsonObject.getString("msg"));
            }
        } else {
            //网络超时
            logger.error("网络超时");
            throw new RuntimeException("网络超时");
        }
    }

    /**
     * 获取泛微token方法
     *
     * @param getAccessTokenPath
     * @param params
     * @return
     * @throws IOException
     */
    public static String getAccessToken(String getAccessTokenPath, Map<String, String> params)
            throws IOException {
        logger.error("getAccessToken方法参数: " + params);
        String url = appendUrl(getAccessTokenPath, params);
        logger.error("access_token url" + url);
        OkHttpClient client = new OkHttpClient();
        Request request = new Request.Builder()
                .url(url)
                .get()
                .addHeader("content-type", "multipart/form-data; boundary=---011000010111000001101001")
                .build();
        Response response = client.newCall(request).execute();
        if (response.isSuccessful()) {
            String string = response.body().string();
            JSONObject jsonObject = JSONObject.parseObject(string);
            String code = jsonObject.getString("code");
            if ("0".equals(code)) {
                String access_token = jsonObject.getString("access_token");
                logger.error("access_token " + access_token);
                return access_token;
            } else {
                throw new RuntimeException(jsonObject.getString("msg"));
            }
        } else {
            //网络超时
            throw new RuntimeException("获取token超时");
        }
    }


    /**
     * 拼接地址参数
     */
    public static String appendUrl(String url, Map<String, String> data) {
        logger.error("appendUrl_url: " + url);
        logger.error("appendUrl_data: " + data);
        StringBuilder paramStr = new StringBuilder();
        for (String key : data.keySet()) {
            paramStr.append(key).append("=").append(data.get(key)).append("&");
        }
        paramStr.deleteCharAt(paramStr.lastIndexOf("&"));
        String str = url.contains("?") ? (url + "&" + paramStr) : (url + "?" + paramStr);
        logger.error("拼接后的地址为:" + str);
        return str;
    }
}
