package nckd.jimin.jyyy.fi.plugin.operate;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import kd.bos.dataentity.entity.DynamicObject;
import kd.bos.logging.Log;
import kd.bos.logging.LogFactory;
import kd.bos.orm.query.QCP;
import kd.bos.orm.query.QFilter;
import kd.bos.sdk.util.KHttpClientUtils;
import kd.bos.servicehelper.BusinessDataServiceHelper;
import kd.bos.servicehelper.operation.SaveServiceHelper;
import kd.bos.servicehelper.user.UserServiceHelper;
import kd.bos.util.StringUtils;
import nckd.base.helper.CommonHelperUtils;
import okhttp3.*;
import javax.crypto.Cipher;
import java.io.IOException;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.interfaces.RSAPrivateKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 插件说明：SRM系统帮助类
 * @author wanghaiwu_kd
 * @date 2025/05/12
 */
public class SRMHelperUtils {
    private static final Log logger = LogFactory.getLog(SRMHelperUtils.class);

    private static int timeout = 180;//超时时间（次/秒）

    /**
     *
     * @param entityName
     * @param billId
     * @param operatorType
     * @return
     */
    public static Map<String, String> writeBackSRMWfStatus(String entityName, Long billId, String operatorType){
        Map<String, String> returnMap = new HashMap<>();
        if(StringUtils.isEmpty(entityName) || billId == null || billId == 0L){
            returnMap.put("code", "1");
            returnMap.put("msg", "回写失败，参数为空");

            return returnMap;
        }

        String selectProperties = "id, billno, billstatus, nckd_srmbillno, nckd_srmurl";
        DynamicObject billInfo = BusinessDataServiceHelper.loadSingle(billId, entityName, selectProperties);

        //退回
        if("nckd_returnsrm".equals(operatorType)){
            //判断单据状态是否等于暂存
            String billStatus = billInfo.getString("billstatus");
            if(!"A".equals(billStatus)){
                returnMap.put("code", "1");
                returnMap.put("msg", "退回失败，单据不是暂存状态");

                return returnMap;
            }
            String srmBillNo = billInfo.getString("nckd_srmbillno");
            if(StringUtils.isEmpty(srmBillNo)){
                returnMap.put("code", "1");
                returnMap.put("msg", "退回失败，单据(" + billInfo.getString("billno") + ")不是由SRM系统生成");

                return returnMap;
            }

            String srmurl = billInfo.getString("nckd_srmurl");
            if(StringUtils.isEmpty(srmurl)){
                returnMap.put("code", "1");
                returnMap.put("msg", "退回失败，单据(" + billInfo.getString("billno") + ")的srm单点url为空");

                return returnMap;
            }

            Map<String,String> doReturnMap = writeReturnStatus(srmBillNo);

            //退回成功后单点到srm
            if (!"0".equals(doReturnMap.get("code"))) {//调接口异常
                return doReturnMap;
            } else {//调接口成功后，获取单点登录链接
                try {
                    billInfo.set("billstatus", "H");

                    SaveServiceHelper.update(new DynamicObject[]{billInfo});
                } catch (Exception e){
                    returnMap.put("code", "1");
                    returnMap.put("msg", "单据(" + billInfo.getString("billno") + ")作废失败：" + e.getMessage());

                    return returnMap;
                }

                return doReturnMap;
            }
        }

        returnMap.put("code", "1");
        returnMap.put("msg", "回写失败");

        return returnMap;
    }

    /**
     * 退回处理
     * @param srmBillNo
     * @return
     */
    public static Map<String,String> writeReturnStatus(String srmBillNo) {
        Map<String,String> returnMap = new HashMap<>();
        //获取token
        Map<String,String> tokenMap = getSRMToken();
        if (!"0".equals(tokenMap.get("code"))) {//未获取到token
            returnMap.put("code", "1");
            returnMap.put("msg", tokenMap.get("msg"));

            return returnMap;
        }
        String token = tokenMap.get("msg").toString();

        Map<String, String> mapentity = CommonHelperUtils.getCommonParams("SRM");
        if(mapentity == null ){
            logger.info("SRMHelperUtils：nckd_entryentity is null");

            returnMap.put("code", "1");
            returnMap.put("msg", "未配置SRM系统对接参数！");
            return returnMap;
        }

        String serverUrlApi = mapentity.get("apiserverurl");
        String writeBillStatusApi = mapentity.get("apiwritebillstatus");
        String userName = mapentity.get("username");//用户名（srm提供）
        String interfaceCode = mapentity.get("interfacecodewritebillstatus");//接口编码（srm提供，不同接口编码不同）
        String externalSysCode = mapentity.get("externalsyscode");//外部系统（srm提供）
        String applicationCode = mapentity.get("applicationcode");//应用（srm提供）
        String applicationGroupCode = mapentity.get("applicationgroupcode");//应用组（srm提供）

        if(StringUtils.isEmpty(serverUrlApi) || StringUtils.isEmpty(writeBillStatusApi) || StringUtils.isEmpty(userName)
                || StringUtils.isEmpty(interfaceCode) ||StringUtils.isEmpty(externalSysCode)
                || StringUtils.isEmpty(applicationCode) || StringUtils.isEmpty(applicationGroupCode)){
            returnMap.put("code", "1");
            returnMap.put("msg", "请检查是否配置SRM参数：服务地址、回写审批状态接口、用户名、接口编码、外部系统、应用编码、应用组");
            return returnMap;
        }

        String url = serverUrlApi + writeBillStatusApi;
        String timestamp = String.valueOf(System.currentTimeMillis());

        JSONObject headerObj = new JSONObject();
        headerObj.put("applicationCode", applicationCode);
        headerObj.put("applicationGroupCode", applicationGroupCode);
        headerObj.put("batchNum", timestamp);
        headerObj.put("externalSystemCode", externalSysCode);
        headerObj.put("interfaceCode", interfaceCode);
        headerObj.put("userName", userName);

        JSONArray bodyArr = new JSONArray();
        JSONObject bodyObj = new JSONObject();

        bodyObj.put("settleNum", srmBillNo);//SRM单据编号
        bodyObj.put("settleStatus", "REJECTED");//APPROVED 已审批 / REJECTED 已拒绝
        bodyObj.put("documentType", "PAYMENT");//PAYMENT 付款   PREPAYMENT 预付款
        bodyObj.put("approvedRemark", "退回");//审批意见

        JSONArray lineNumArr = new JSONArray();
        JSONObject lineNumObj = new JSONObject();
        lineNumObj.put("lineNum", 1);
        lineNumArr.add(lineNumObj);

        bodyObj.put("settleReversalLines", lineNumArr);//结算单行


        bodyArr.add(bodyObj);

        JSONObject body=new JSONObject();
        body.put("header", headerObj);
        body.put("body", bodyArr);

        Map<String, String> headerMap = new HashMap<>();
        headerMap.put("Content-Type", "application/json");
        headerMap.put("User-Agent", "apifox/1.0.0 (https://www.apifox.cn)");
        headerMap.put("Authorization", "Bearer " + token);

        logger.info("srm退回 " + srmBillNo + ", header：" + headerMap.toString());
        logger.info("srm退回 " + srmBillNo + ", body：" + body.toJSONString());

        try {
//            String response = doHttpClientPost(url,  body.toJSONString(), token);
            String response = KHttpClientUtils.postjson(url, headerMap, body.toJSONString());

            if(StringUtils.isEmpty(response)){
                returnMap.put("code", "1");
                returnMap.put("msg", "退回失败, 返回为空");

                return returnMap;
            }

            JSONObject resultJSON = JSONObject.parseObject(response);

            if (resultJSON !=null && "SUCCESS".equals(resultJSON.get("responseStatus").toString())
                    &&"SUCCESS".equals(resultJSON.get("executeResult").toString())) {
                returnMap.put("code","0");
                returnMap.put("msg","退回成功");
            } else{
                returnMap.put("code","1");
                returnMap.put("msg", "退回失败" + response);
            }

            return returnMap;
        } catch(IOException e){
            returnMap.put("code", "1");
            returnMap.put("msg", "获取token失败, " + e.getMessage());

            return returnMap;
        } catch(Exception e){
            returnMap.put("code", "1");
            returnMap.put("msg", "获取token失败, " + e.getMessage());

            return returnMap;
        }
    }

    /**
     * 回写审批结果
     * @param srmBillNo
     * @return
     */
    public static Map<String,String> writeApproveStatus(String srmBillNo, String documentType) {
        Map<String,String> returnMap = new HashMap<>();
        //获取token
        Map<String,String> tokenMap = getSRMToken();
        if (!"0".equals(tokenMap.get("code"))) {//未获取到token
            returnMap.put("code", "1");
            returnMap.put("msg", tokenMap.get("msg"));

            return returnMap;
        }
        String token = tokenMap.get("msg").toString();

        Map<String, String> mapentity = CommonHelperUtils.getCommonParams("SRM");
        if(mapentity == null ){
            logger.info("SRMHelperUtils：nckd_entryentity is null");

            returnMap.put("code", "1");
            returnMap.put("msg", "未配置SRM系统对接参数！");
            return returnMap;
        }

        String serverUrlApi = mapentity.get("apiserverurl");
        String writeBillStatusApi = mapentity.get("apiwritebillstatus");
        String userName = mapentity.get("username");//用户名（srm提供）
        String interfaceCode = mapentity.get("interfacecodewritebillstatus");//接口编码（srm提供，不同接口编码不同）
        String externalSysCode = mapentity.get("externalsyscode");//外部系统（srm提供）
        String applicationCode = mapentity.get("applicationcode");//应用（srm提供）
        String applicationGroupCode = mapentity.get("applicationgroupcode");//应用组（srm提供）

        if(StringUtils.isEmpty(serverUrlApi) || StringUtils.isEmpty(writeBillStatusApi) || StringUtils.isEmpty(userName)
                || StringUtils.isEmpty(interfaceCode) ||StringUtils.isEmpty(externalSysCode)
                || StringUtils.isEmpty(applicationCode) || StringUtils.isEmpty(applicationGroupCode)){
            returnMap.put("code", "1");
            returnMap.put("msg", "请检查是否配置SRM参数：服务地址、回写审批状态接口、用户名、接口编码、外部系统、应用编码、应用组");
            return returnMap;
        }

        String url = serverUrlApi + writeBillStatusApi;
        String timestamp = String.valueOf(System.currentTimeMillis());

        JSONObject headerObj = new JSONObject();
        headerObj.put("applicationCode", applicationCode);
        headerObj.put("applicationGroupCode", applicationGroupCode);
        headerObj.put("batchNum", timestamp);
        headerObj.put("externalSystemCode", externalSysCode);
        headerObj.put("interfaceCode", interfaceCode);
        headerObj.put("userName", userName);

        JSONArray bodyArr = new JSONArray();
        JSONObject bodyObj = new JSONObject();

        bodyObj.put("settleNum", srmBillNo);//SRM单据编号
        bodyObj.put("settleStatus", "APPROVED");//APPROVED 已审批 / REJECTED 已拒绝
        bodyObj.put("documentType", documentType);//PAYMENT 付款   PREPAYMENT 预付款
        bodyObj.put("approvedRemark", "通过");//审批意见

        JSONArray lineNumArr = new JSONArray();
        JSONObject lineNumObj = new JSONObject();
        lineNumObj.put("lineNum", 1);
        lineNumArr.add(lineNumObj);

        bodyObj.put("settleReversalLines", lineNumArr);//结算单行


        bodyArr.add(bodyObj);

        JSONObject body=new JSONObject();
        body.put("header", headerObj);
        body.put("body", bodyArr);

        Map<String, String> headerMap = new HashMap<>();
        headerMap.put("Content-Type", "application/json");
        headerMap.put("User-Agent", "apifox/1.0.0 (https://www.apifox.cn)");
        headerMap.put("Authorization", "Bearer " + token);

        logger.info("SRMHelperUtils writeApproveStatus：body " + body.toJSONString());
        logger.info("SRMHelperUtils writeApproveStatus：header " + headerMap.toString());

        try {
//            String response = doHttpClientPost(url,  body.toJSONString(), token);
            String response = KHttpClientUtils.postjson(url, headerMap, body.toJSONString());

            if(StringUtils.isEmpty(response)){
                returnMap.put("code", "1");
                returnMap.put("msg", "回写审批结果失败, 返回为空");

                return returnMap;
            }

            JSONObject resultJSON = JSONObject.parseObject(response);

            if (resultJSON !=null && "SUCCESS".equals(resultJSON.get("responseStatus").toString())
                    &&"SUCCESS".equals(resultJSON.get("executeResult").toString())) {
                returnMap.put("code","回写审批结果成功");
            } else{
                returnMap.put("code","1");
                returnMap.put("msg", "回写审批结果失败" + response);
            }

            return returnMap;
        } catch(IOException e){
            returnMap.put("code", "1");
            returnMap.put("msg", "获取token失败, " + e.getMessage());

            return returnMap;
        } catch(Exception e){
            returnMap.put("code", "1");
            returnMap.put("msg", "获取token失败, " + e.getMessage());

            return returnMap;
        }
    }

    /**
     * 同步付款信息至SRM
     * @param srmBillNo
     * @param paymentDate
     * @param paymentAmount
     * @return
     */
    public static Map<String,String> writeBackPayResulst(String srmBillNo, String paymentDate, BigDecimal paymentAmount) {
        Map<String,String> returnMap = new HashMap<>();
        //获取token
        Map<String,String> tokenMap = getSRMToken();
        if (!"0".equals(tokenMap.get("code"))) {//未获取到token
            returnMap.put("code", "1");
            returnMap.put("msg", tokenMap.get("msg"));

            logger.info("SRMHelperUtils：获取token异常" + returnMap.toString());

            return returnMap;
        }
        String token = tokenMap.get("msg").toString();

        Map<String, String> mapentity = CommonHelperUtils.getCommonParams("SRM");
        if(mapentity == null ){
            logger.info("SRMHelperUtils：nckd_entryentity is null");

            returnMap.put("code", "1");
            returnMap.put("msg", "未配置SRM系统对接参数！");
            return returnMap;
        }

        String serverUrlApi = mapentity.get("apiserverurl");
        String writePayResultApi = mapentity.get("apiwritepayresult");
        String userName = mapentity.get("username");//用户名（srm提供）
        String interfaceCode = mapentity.get("interfacecodewritebillstatus");//接口编码（srm提供，不同接口编码不同）
        String externalSysCode = mapentity.get("externalsyscode");//外部系统（srm提供）
        String applicationCode = mapentity.get("applicationcode");//应用（srm提供）
        String applicationGroupCode = mapentity.get("applicationgroupcode");//应用组（srm提供）

        if(StringUtils.isEmpty(serverUrlApi) || StringUtils.isEmpty(writePayResultApi) || StringUtils.isEmpty(userName)
                || StringUtils.isEmpty(interfaceCode) ||StringUtils.isEmpty(externalSysCode)
                || StringUtils.isEmpty(applicationCode) || StringUtils.isEmpty(applicationGroupCode)){
            returnMap.put("code", "1");
            returnMap.put("msg", "请检查是否配置SRM参数：服务地址、付款结果回写接口、用户名、接口编码、外部系统、应用编码、应用组");

            logger.info("SRMHelperUtils：同步失败" + returnMap);

            return returnMap;
        }

        String url = serverUrlApi + writePayResultApi;
        String timestamp = String.valueOf(System.currentTimeMillis());

        JSONObject headerObj = new JSONObject();
        headerObj.put("applicationCode", applicationCode);
        headerObj.put("applicationGroupCode", applicationGroupCode);
        headerObj.put("batchCount", "1");
        headerObj.put("batchNum", timestamp);
        headerObj.put("externalSystemCode", externalSysCode);
        headerObj.put("interfaceCode", interfaceCode);
        headerObj.put("userName", userName);

        JSONArray bodyArr = new JSONArray();
        JSONObject bodyObj = new JSONObject();

        bodyObj.put("settleNum", srmBillNo);//SRM单据编号
        bodyObj.put("paymentType", "PAYMENT");//PAYMENT 付款；PREPAYMENT　预付款
        bodyObj.put("paymentDate", paymentDate);//付款日期
        bodyObj.put("paymentAmount",paymentAmount);//付款金额

        bodyArr.add(bodyObj);

        JSONObject body=new JSONObject();
        body.put("header", headerObj);
        body.put("body", bodyArr);

        Map<String, String> headerMap = new HashMap<>();
        headerMap.put("Content-Type", "application/json");
        headerMap.put("User-Agent", "apifox/1.0.0 (https://www.apifox.cn)");
        headerMap.put("Authorization", "Bearer " + token);

        logger.info("SRMHelperUtils writeBackPayResulst：body " + body.toJSONString());
        logger.info("SRMHelperUtils writeBackPayResulst：header " + headerMap.toString());

        try {
            String response = KHttpClientUtils.postjson(url, headerMap, body.toJSONString());

            if(StringUtils.isEmpty(response)){
                returnMap.put("code", "1");
                returnMap.put("msg", "回写付款状态失败, 返回为空");

                return returnMap;
            }

            JSONObject resultJSON = JSONObject.parseObject(response);

            if (resultJSON !=null && "SUCCESS".equals(resultJSON.get("responseStatus").toString())
                    &&"SUCCESS".equals(resultJSON.get("executeResult").toString())) {
                returnMap.put("code","0");

                returnMap.put("msg", "回写成功");
            } else{
                returnMap.put("code","1");
                returnMap.put("msg", "回写付款状态失败" + response);
            }

            return returnMap;
        } catch(IOException e){
            returnMap.put("code", "1");
            returnMap.put("msg", "获取token失败, " + e.getMessage());

            return returnMap;
        } catch(Exception e){
            returnMap.put("code", "1");
            returnMap.put("msg", "获取token失败, " + e.getMessage());

            return returnMap;
        }
    }

    /**
     * 构造单点url
     * @param srmUrl
     * @return
     */
    public static Map<String,String> buildSSOUrl(String srmUrl) {
        Map<String,String> returnMap = new HashMap<>();

        Map<String, String> mapentity = CommonHelperUtils.getCommonParams("SRM");
        if(mapentity == null ){
            logger.info("SRMHelperUtils：nckd_entryentity is null");

            returnMap.put("code", "1");
            returnMap.put("msg", "未配置SRM系统对接参数！");
            return returnMap;
        }

        String serverUrl = mapentity.get("serverurl");//服务地址
        String ssoUrl = mapentity.get("ssourl");//单点地址
        String privateKey = mapentity.get("ssoprivate");//单点私钥

        if(StringUtils.isEmpty(serverUrl) || StringUtils.isEmpty(ssoUrl) || StringUtils.isEmpty(privateKey)){
            returnMap.put("code", "1");
            returnMap.put("msg", "请检查是否配置SRM参数：服务地址、单点地址、单点私钥");
            return returnMap;
        }

        DynamicObject  userInfo =  UserServiceHelper.getUserInfoByID(UserServiceHelper.getCurrentUserId(),"number,username");
        String userNumber = userInfo.getString("number");

        try {
            String userName = encrypt(userNumber, privateKey);
            String url = serverUrl + ssoUrl + "?username=" + userName + "&redirectUri=" + srmUrl;

            returnMap.put("code", "0");
            returnMap.put("msg", url);

            logger.info("SRMHelperUtils：获取srm单点url：" + returnMap.toString());

            return returnMap;
        } catch(Exception e){
            returnMap.put("code", "1");
            returnMap.put("msg", e.getMessage());
            return returnMap;
        }
    }

    /**
     * 对用户加密
     * @param content
     * @param keyStr
     * @return
     * @throws Exception
     */
    public static String encrypt(String content, String keyStr) throws Exception {
        long nowTime = System.currentTimeMillis(); //获取当前时间戳拼接加密，加密内容使用有效期3分钟
        String contentWithTime = content + "|" + String.valueOf(nowTime);
        Cipher cipher = Cipher.getInstance("RSA");
        RSAPrivateKey privateKey = getPrivateKey(keyStr);
        cipher.init(1, privateKey);
        return SRMBase64Util.getUrlEncoder().encodeToString(cipher.doFinal(contentWithTime.getBytes("UTF-8")));//StandardCharsets.UTF_8

    }

    /**
     * 获取私钥
     * @param privateKey
     * @return
     * @throws Exception
     */
    private static RSAPrivateKey getPrivateKey(String privateKey) throws  Exception {
        try {
            return (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(SRMBase64Util.getDecoder().decode(privateKey)));
        } catch (Exception var2) {
            System.out.println("RSA get Private Key failed!"+var2.toString());
            throw new Exception(var2);
        }
    }

    /**
     * 私钥加密
     *
     * @param content 加密内容
     * @param keyStr  私钥
     * @return
     */
    public static String encryptOld(String content, String keyStr) {
        try {
            //获取当前时间戳拼接加密，加密内容使用有效期3分钟
            long nowTime = System.currentTimeMillis();
            String contentWithTime = content + "|" + String.valueOf(nowTime);
            Cipher cipher = Cipher.getInstance("RSA");
            RSAPrivateKey privateKey = getPrivateKeyOld(keyStr);
            cipher.init(1, privateKey);
            return Base64.getUrlEncoder().encodeToString(cipher.doFinal(contentWithTime.getBytes(StandardCharsets.UTF_8)));
        } catch (Exception var3) {
            throw new RuntimeException("RSA encrypt failed!", var3);
        }
    }


    private static RSAPrivateKey getPrivateKeyOld(String privateKey) {
        try {
            return (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKey)));
        } catch (Exception var2) {
            throw new RuntimeException("RSA get Private Key failed!", var2);
        }
    }

    /**
     * 获取SRM token
     * @return
     */
    public static Map<String,String> getSRMToken() {
        Map<String,String> returnMap = new HashMap<>();

        Map<String, String> mapentity = CommonHelperUtils.getCommonParams("SRM");
        if(mapentity == null ){
            logger.info("SRMHelperUtils：nckd_entryentity is null");

            returnMap.put("code", "1");
            returnMap.put("msg", "未配置SRM系统对接参数！");
            return returnMap;
        }

        String serverUrlApi = mapentity.get("apiserverurl");
        String getTokenApi = mapentity.get("apigettoken");
        String grantType = mapentity.get("granttype");
        String clientId = mapentity.get("clientid");
        String clientSecret = mapentity.get("clientsecret");
        String scope = mapentity.get("scope");


        if(StringUtils.isEmpty(serverUrlApi) || StringUtils.isEmpty(getTokenApi) || StringUtils.isEmpty(grantType)
                || StringUtils.isEmpty(clientId) ||StringUtils.isEmpty(clientSecret) || StringUtils.isEmpty(scope) ){
            returnMap.put("code", "1");
            returnMap.put("msg", "请检查是否配置SRM参数：服务地址、授权模式、客户端ID、客户端密钥、作用域、获取token接口");
            return returnMap;
        }

        String tokenUrl = serverUrlApi + getTokenApi + "?grant_type=" + grantType + "&client_id=" + clientId + "&client_secret=" + clientSecret + "&scope=" + scope;

        try {
            JSONObject jsonData = new JSONObject();
            String response = KHttpClientUtils.postjson(tokenUrl, null, jsonData.toJSONString());
            if(StringUtils.isEmpty(response)){
                returnMap.put("code", "1");
                returnMap.put("msg", "获取token失败, getToken返回为空");

                return returnMap;
            }

            JSONObject resultJSON = JSONObject.parseObject(response);
            if (resultJSON !=null &&!StringUtils.isEmpty(resultJSON.get("access_token").toString())) {
                returnMap.put("code", "0");
                returnMap.put("msg", resultJSON.get("access_token").toString());
            } else{
                returnMap.put("code","1");
                returnMap.put("msg", response);
            }

            return returnMap;
        } catch(IOException e){
            returnMap.put("code", "1");
            returnMap.put("msg", "获取token失败, " + e.getMessage());

            return returnMap;
        } catch(Exception e){
            returnMap.put("code", "1");
            returnMap.put("msg", "获取token失败, " + e.getMessage());

            return returnMap;
        }
    }
}
