package com.yeejoin.amos.boot.module.statistcs.biz.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.yeejoin.amos.boot.biz.common.entity.DataDictionary;
import com.yeejoin.amos.boot.biz.common.service.impl.DataDictionaryServiceImpl;
import com.yeejoin.amos.boot.biz.common.utils.JsonValueUtils;
import com.yeejoin.amos.boot.biz.common.utils.RestTemplateUtils;
import com.yeejoin.amos.boot.biz.common.utils.StringUtils;
import com.yeejoin.amos.boot.module.statistcs.biz.utils.DpSubUtils;
import com.yeejoin.amos.feign.morphic.Morphic;
import com.yeejoin.amos.feign.morphic.model.FormSceneModel;
import jdk.nashorn.api.scripting.ScriptObjectMirror;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.client.RestTemplate;
import org.typroject.tyboot.core.foundation.context.RequestContext;
import org.typroject.tyboot.core.foundation.utils.DateUtil;
import org.typroject.tyboot.core.foundation.utils.ValidationUtil;
import org.typroject.tyboot.core.restful.utils.ResponseModel;

import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import java.net.URI;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 大屏二级页面实现类
 *
 * @author Administrator
 */
@Slf4j
@Service
public class DPSubServiceImpl {

    private static final String GATEWAY_SERVER_NAME = "AMOS-SERVER-GATEWAY";

    @Autowired
    @LoadBalanced
    private RestTemplate restTemplate;

    @Autowired
    DataDictionaryServiceImpl iDataDictionaryService;

    public JSONObject commonQuery(String template, @RequestBody Map<String, Object> param) {
        JSONObject result = new JSONObject();
        String templateJson = DpSubUtils.getFileContent(template + ".json");

        //1、替换json中所有的变量
        if (!ValidationUtil.isEmpty(param)) {
            for (Map.Entry item : param.entrySet()) {
                templateJson = templateJson.replaceAll("\\{" + item.getKey() + "\\}", item.getValue().toString());
            }
        }
        //2、解析结构
        result = JSON.parseObject(templateJson);
        JSONArray tabs = result.getJSONArray("tabs");
        JSONObject content = result.getJSONObject("content");
        tabs.stream().forEach(x -> {
            JSONObject tab = (JSONObject) x;
            long s = System.currentTimeMillis();
            this.buildContent(content, tab, param);
            long e = System.currentTimeMillis();
            log.info("{}tab页处理结束，共耗时：{} 毫秒", tab.get("displayName"), (e - s));
        });
        return result;
    }

    public void buildContent(JSONObject content, JSONObject tab, Map<String, Object> param) {
        Long formSeq = tab.getLong("formSeq");
        String renderType = tab.getString("renderType");
        Object resultConvert = JsonValueUtils.getValueByKey(tab, "dataConfig", "dataConfig.resultConvert");
        Object api = JsonValueUtils.getValueByKey(tab, "dataConfig", "dataConfig.api");
        tab.put("param", param);

        JSONObject map = content.getJSONObject(tab.getString("key"));
        if (ValidationUtil.isEmpty(map)){
            map = new JSONObject();
        }
        Object apiResult = null;

        if (!ValidationUtil.isEmpty(api)) {
            long s = System.currentTimeMillis();
            ResponseModel responseModel = this.getApiResult((JSONObject) api, !ValidationUtil.isEmpty(resultConvert) ? resultConvert.toString() : null);
            if (!ValidationUtil.isEmpty(responseModel.getResult())) {
                apiResult = responseModel.getResult();
            }
            long e = System.currentTimeMillis();
            log.info("{}tab页获取详情接口，共耗时：{} 毫秒", tab.get("displayName"), (e - s));
        }

        if (!ValidationUtil.isEmpty(formSeq)) {
            long s = System.currentTimeMillis();
            FormSceneModel formPage = Morphic.formSceneClient.seleteOne(formSeq).getResult();
            // 1、排除表单隐藏字段
            JSONArray children = (JSONArray) JsonValueUtils.getValueByKey(JSONObject.parseObject(formPage.getContent()), "children", "children");
            Object showHideRules = JsonValueUtils.getValueByKey(JSONObject.parseObject(formPage.getContent()), "formConfig", "formConfig.showHideRules");

            // 处理显隐逻辑
            this.processShowHideRules(children, showHideRules, apiResult);
            long e = System.currentTimeMillis();
            log.info("{}tab页处理显隐逻辑，共耗时：{} 毫秒", tab.get("displayName"), (e - s));

            List<Object> noHiddenChildren = children.stream().filter(x -> !"hidden".equals(JsonValueUtils.getValueByKey(x, "visualParams", "visualParams.behavior"))).collect(Collectors.toList());
            // 设置一个图片附件分组
            JSONObject matinfo = new JSONObject();
            matinfo.put("displayName", "图片附件");
            matinfo.put("renderType", "matui");
            matinfo.put("datas", new JSONArray());

            for (int i = 0; i < noHiddenChildren.size(); i++) {
                JSONObject yObj = (JSONObject) noHiddenChildren.get(i);

                if ("pageSection".equals(yObj.get("componentKey")) || "columnsLayout".equals(yObj.get("componentKey"))) { // 分组或者布局容器
                    List<Object> mergedArray = mergedList(yObj.getJSONArray("children"));
                    // 第一组去除标题
                    if (i == 0 || ValidationUtil.isEmpty(map.get("datas"))) {
                        this.buildContentData(tab, map, mergedArray, apiResult, matinfo);
                    } else {
                        this.buildSubContentData(tab, map, i, yObj, mergedArray, apiResult, matinfo);
                    }
                } else if ("subForm".equals(yObj.get("componentKey"))) { // 子表单
                    this.buildSubFormData(map, i, yObj, apiResult);
                }
            }
            long fe = System.currentTimeMillis();
            log.info("{}tab页处理分类逻辑，共耗时：{} 毫秒", tab.get("displayName"), (fe - e));
            if (!ValidationUtil.isEmpty(matinfo.getJSONArray("datas"))) {
                matinfo.put("columns", map.get("columns"));
                map.getJSONArray("subs").add(matinfo);
            }
        } else {
            if ("timeline".equals(renderType)){
                content.put(tab.getString("key"), apiResult);
            } else if("table".equals(renderType)){
                Object columns = JsonValueUtils.getValueByKey(tab, "visualParams", "visualParams.columns");
                map.put("columns", columns);
                map.put("dataList", apiResult);
                map.put("showPage", true);
                map.put("api", api);
                map.put("rowKey", JsonValueUtils.getValueByKey(tab, "visualParams", "visualParams.rowKey"));
                content.put(tab.getString("key"), map);
            }
        }
    }

    private JSONArray processShowHideRules(JSONArray children, Object showHideRules, Object apiResult) {
        JSONObject result = JSONObject.parseObject(apiResult.toString());
        if (!ValidationUtil.isEmpty(showHideRules)) {
            ((JSONArray) showHideRules).stream().forEach(x -> {
                JSONObject xObj = (JSONObject) x;
                boolean hide = true;
                JSONArray conditions = xObj.getJSONArray("condition");
                String relation = null;
                boolean lastConditionResult = false;
                for (int i = 0; i < conditions.size(); i++) {
                    JSONObject conditionObj = conditions.getJSONObject(i);
                    String value = conditionObj.getString("value");
                    String condition = conditionObj.getString("condition");
                    JSONObject item = this.findByEid(children, JsonValueUtils.getValueByKey(conditionObj, "name", "name.key").toString());

                    Object fieldvalue = result.get(JsonValueUtils.getValueByKey(item, "visualParams", "visualParams.fieldKey"));
                    if (ValidationUtil.isEmpty(relation)) {
                        if (condition.equals("notUndefined") && !ValidationUtil.isEmpty(fieldvalue)) {
                            lastConditionResult = !ValidationUtil.isEmpty(fieldvalue);
                            hide = false;
                        } else if (condition.equals("unequal") && !ValidationUtil.isEmpty(fieldvalue) && !fieldvalue.equals(value)) {
                            lastConditionResult = !fieldvalue.equals(value);
                            hide = false;
                        } else if (condition.equals("equal") && !ValidationUtil.isEmpty(fieldvalue) && fieldvalue.equals(value)) {
                            lastConditionResult = fieldvalue.equals(value);
                            hide = false;
                        }
                    } else {
                        if (lastConditionResult && condition.equals("notUndefined") && !ValidationUtil.isEmpty(fieldvalue)) {
                            lastConditionResult = !ValidationUtil.isEmpty(fieldvalue);
                            hide = false;
                        } else if (lastConditionResult && condition.equals("unequal") && !ValidationUtil.isEmpty(fieldvalue) && !fieldvalue.equals(value)) {
                            lastConditionResult = !fieldvalue.equals(value);
                            hide = false;
                        } else if (lastConditionResult && condition.equals("equal") && !ValidationUtil.isEmpty(fieldvalue) && fieldvalue.equals(value)) {
                            lastConditionResult = fieldvalue.equals(value);
                            hide = false;
                        } else {
                            hide = true;
                        }
                    }
                    relation = conditionObj.getString("relation");
                }

                if (hide) {
                    JSONArray showColumns = xObj.getJSONArray("showColumns");
                    showColumns.stream().forEach(showColumn -> {
                        boolean match = false; // 是否匹配标识
                        List<Object> collect = children.stream().filter(y -> showColumn.equals(JsonValueUtils.getValueByKey(y, "eid", "eid"))).collect(Collectors.toList());

                        if (ValidationUtil.isEmpty(collect)) {
                            for (int i = 0; i < children.size(); i++) {
                                if (match) {
                                    break;
                                }
                                JSONArray subChildren = children.getJSONObject(i).getJSONArray("children");
                                for (int j = 0; j < subChildren.size(); j++) {
                                    if (match) {
                                        break;
                                    }
                                    Object cchildren = JsonValueUtils.getValueByKey(subChildren.get(j), "children", "children");
                                    if (!ValidationUtil.isEmpty(cchildren)) {
                                        List<Object> ccollect = ((JSONArray) cchildren).stream().filter(y -> showColumn.equals(JsonValueUtils.getValueByKey(y, "eid", "eid"))).collect(Collectors.toList());
                                        if (!ValidationUtil.isEmpty(ccollect)) {
                                            JSONObject groupObj = (JSONObject) ccollect.get(0);
                                            JSONObject visualParams = groupObj.getJSONObject("visualParams");
                                            visualParams.put("behavior", "hidden");
                                            match = true;
                                            break;
                                        }
                                    }
                                }
                            }
                        } else {
                            JSONObject groupObj = (JSONObject) collect.get(0);
                            JSONObject visualParams = groupObj.getJSONObject("visualParams");
                            visualParams.put("behavior", "hidden");
                        }
                    });
                }
            });
        }
        return children;
    }

    private JSONObject findByEid(JSONArray children, String eid) {
        List<Object> collect = children.stream().filter(x -> eid.equals(JsonValueUtils.getValueByKey(x, "eid", "eid"))).collect(Collectors.toList());
        if (ValidationUtil.isEmpty(collect)) {
            for (int i = 0; i < children.size(); i++) {
                JSONArray subChildren = children.getJSONObject(i).getJSONArray("children");
                for (int j = 0; j < subChildren.size(); j++) {
                    if (ValidationUtil.isEmpty(subChildren.getJSONObject(j).get("children"))) {
                        List<Object> ccollect = subChildren.stream().filter(y -> eid.equals(JsonValueUtils.getValueByKey(y, "eid", "eid"))).collect(Collectors.toList());
                        if (!ValidationUtil.isEmpty(ccollect)) {
                            return (JSONObject) ccollect.get(0);
                        }
                    } else {
                        Object cchildren = JsonValueUtils.getValueByKey(subChildren.get(j), "children", "children");
                        if (!ValidationUtil.isEmpty(cchildren)) {
                            List<Object> ccollect = ((JSONArray) cchildren).stream().filter(y -> eid.equals(JsonValueUtils.getValueByKey(y, "eid", "eid"))).collect(Collectors.toList());
                            if (!ValidationUtil.isEmpty(ccollect)) {
                                return (JSONObject) ccollect.get(0);
                            }
                        }
                    }
                }
            }
        }
        return !ValidationUtil.isEmpty(collect) ? (JSONObject) collect.get(0) : null;
    }

    /**
     * 合并分组组件下的所有组件
     *
     * @param children
     * @return
     */
    private List<Object> mergedList(JSONArray children) {
        JSONArray mergedArray = new JSONArray();
        int maxSize = 0; // 初始化为JSONArray的长度
        for (int i = 0; i < children.size(); i++) {
            JSONArray cchildren = children.getJSONObject(i).getJSONArray("children");
            if (!ValidationUtil.isEmpty(cchildren)) {
                maxSize = Math.max(maxSize, cchildren.size());
            }
        }

        for (int i = 0; i < maxSize; i++) {
            for (int j = 0; j < children.size(); j++) {
                JSONArray cchildren = children.getJSONObject(j).getJSONArray("children");
                if (!ValidationUtil.isEmpty(cchildren)) {
                    List<Object> noHiddenMergedArray = cchildren.stream().filter(x -> {
                        JSONObject xObj = (JSONObject) x;
                        return !"hidden".equals(JsonValueUtils.getValueByKey(xObj, "visualParams", "visualParams.behavior"));
                    }).collect(Collectors.toList());

                    if (i < noHiddenMergedArray.size()) {
                        mergedArray.add(noHiddenMergedArray.get(i));
                    }
                }
            }
        }
        return mergedArray;
    }

    public JSONObject buildContentData(JSONObject tab, JSONObject map, List<Object> mergedArray, Object apiResult, JSONObject matinfo) {
        JSONObject result = JSONObject.parseObject(apiResult.toString());
        JSONArray datas = new JSONArray();
        // 处理二维码
        mergedArray.stream().filter(x -> "QRCode".equals(JsonValueUtils.getValueByKey(x, "componentKey", null))).findFirst().ifPresent(x -> {
            JSONObject qrcode = map.getJSONObject("qrcode");
            String problemTime = result.getString("problemTime");
            String problemStatus = result.getString("problemStatus");
            String color = null;
            if (!ValidationUtil.isEmpty(problemTime)) {
                try {
                    qrcode.put("text", DateUtil.formatDate(DateUtil.smartFormat(problemTime), "yyyy-MM-dd"));
                    qrcode.put("subtext", DateUtil.formatDate(DateUtil.smartFormat(problemTime), "HH:mm:ss"));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            if ("正常".equals(problemStatus)) {
                color = "green";
            } else if ("异常".equals(problemStatus)) {
                color = "red";
            }
            qrcode.put("value", !ValidationUtil.isEmpty(result.get("useCode")) ? result.get("useCode") : result.get("USE_ORG_CODE"));
            qrcode.put("status", problemStatus);
            qrcode.put("color", color);
        });

        mergedArray = mergedArray.stream().filter(x -> !"QRCode".equals(JsonValueUtils.getValueByKey(x, "componentKey", null))).collect(Collectors.toList());

        mergedArray.stream().forEach(x -> {
            Object fieldKey = JsonValueUtils.getValueByKey(x, "visualParams", "visualParams.fieldKey");
            if (!ValidationUtil.isEmpty(fieldKey)) {
                this.processWidgets(tab, datas, x, null, fieldKey.toString(), result, matinfo);
            }
        });
        map.put("datas", datas);
        return map;
    }

    public JSONObject buildSubContentData(JSONObject tab, JSONObject map, int i, JSONObject yObj, List<Object> mergedArray, Object apiResult, JSONObject matinfo) {
        JSONArray subs = map.getJSONArray("subs");
        JSONArray children = yObj.getJSONArray("children");
        List<Object> columnsArray = children.stream().filter(x -> {
            JSONObject xObj = (JSONObject) x;
            return !ValidationUtil.isEmpty(xObj.getJSONArray("children")) && xObj.getJSONArray("children").size() > 0;
        }).collect(Collectors.toList());

        JSONObject subObj = new JSONObject();
        subObj.put("key", "key" + i);
        Object displayName = JsonValueUtils.getValueByKey(yObj, "visualParams", "visualParams.title");
        subObj.put("displayName", displayName);
        subObj.put("renderType", "basic");
        subObj.put("columns", columnsArray.size());

        JSONArray datas = new JSONArray();
        mergedArray.stream().forEach(x -> {
            Object fieldKey = JsonValueUtils.getValueByKey(x, "visualParams", "visualParams.fieldKey");
            if (!ValidationUtil.isEmpty(fieldKey)) {
                this.processWidgets(tab, datas, x, displayName, fieldKey.toString(), JSONObject.parseObject(apiResult.toString()), matinfo);
                subObj.put("datas", datas);
            }
        });
        subs.add(subObj);
        return map;
    }

    /**
     * 处理不同组件的展示
     *
     * @param datas
     * @param x
     * @param fieldKey
     * @param apiResult
     * @return
     */
    public JSONArray processWidgets(JSONObject tab, JSONArray datas, Object x, Object displayName, String fieldKey, JSONObject apiResult, JSONObject matinfo) {
        JSONObject jsonObject = new JSONObject();

        JSONObject xObj = (JSONObject) x;
        JSONObject visualParams = xObj.getJSONObject("visualParams");
        jsonObject.put("label", visualParams.getString("label"));
        Object value = apiResult.get(fieldKey);

        Object paramFieldKeys = JsonValueUtils.getValueByKey(tab, "dataConfig", "dataConfig.paramFieldKeys");
        Object dictionaryFieldKeys = JsonValueUtils.getValueByKey(tab, "dataConfig", "dataConfig.dictionaryFieldKeys");
        JSONObject param = tab.getJSONObject("param");
        jsonObject.put("type", "text");
        jsonObject.put("value", value);
        if (!ValidationUtil.isEmpty(paramFieldKeys) && ((JSONArray) paramFieldKeys).contains(fieldKey)){
            jsonObject.put("value", param.getString(fieldKey));
        } else if(!ValidationUtil.isEmpty(dictionaryFieldKeys) && ((JSONArray) dictionaryFieldKeys).stream().anyMatch(map -> fieldKey.equals(((JSONObject) map).getString("fieldKey")))){
            ((JSONArray) dictionaryFieldKeys).stream().filter(map -> fieldKey.equals(((JSONObject) map).getString("fieldKey"))).findFirst().ifPresent(y -> {
                JSONObject yObj = (JSONObject) y;
                String dictionaryType = yObj.getString("dictionaryType");
                try {
                    List<DataDictionary> dataDictionaryList = iDataDictionaryService.getByType(dictionaryType);
                    dataDictionaryList.stream().filter(dataDictionary -> dataDictionary.getCode().equals(value)).findFirst().ifPresent(map -> {
                        jsonObject.put("value", map.getName());
                    });
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            });
        } else {
            if ("upload".equals(xObj.getString("componentKey"))) {
                JSONArray attachmentUploadDatas = matinfo.getJSONArray("datas");
                if (!ValidationUtil.isEmpty(value)) {
                    JSONObject attachmentUploadDatasObj = new JSONObject();
                    String label = visualParams.getString("label");
                    if (!ValidationUtil.isEmpty(displayName)){
                        label = label + "(" + displayName + ")";
                    }
                    attachmentUploadDatasObj.put("label", label);
                    attachmentUploadDatasObj.put("value", value);
                    attachmentUploadDatasObj.put("type", "img");
                    attachmentUploadDatas.add(attachmentUploadDatasObj);
                }
            } else if ("attachmentUpload".equals(xObj.getString("componentKey"))) {
                JSONArray attachmentUploadDatas = matinfo.getJSONArray("datas");
                if (!ValidationUtil.isEmpty(value)) {
                    JSONObject attachmentUploadDatasObj = new JSONObject();
                    attachmentUploadDatasObj.put("value", value);
                    String accept = visualParams.getString("accept");
                    String label = visualParams.getString("label");
                    if (!ValidationUtil.isEmpty(displayName)){
                        label = label + "(" + displayName + ")";
                    }
                    attachmentUploadDatasObj.put("label", label);
                    if (accept.equals(".*") || accept.contains("doc") || accept.contains("docx") || accept.contains("pdf") || accept.contains("xls") || accept.contains("xlsx")){
                        attachmentUploadDatasObj.put("type", "file");
                    } else if(accept.contains("png") || accept.contains("img")){
                        attachmentUploadDatasObj.put("type", "img");
                    } else if(accept.contains("mp4") || accept.contains("flv")){
                        attachmentUploadDatasObj.put("type", "video");
                    }
                    attachmentUploadDatas.add(attachmentUploadDatasObj);
                }
            } else if ("lnglatSelect".equals(xObj.getString("componentKey"))) {
                if (!ValidationUtil.isEmpty(value) && value instanceof JSONObject) {
                    JSONObject lnglatSelect = (JSONObject) value;
                    jsonObject.put("value", (!ValidationUtil.isEmpty(lnglatSelect.getString("latitude")) && !ValidationUtil.isEmpty(lnglatSelect.getString("longitude")))
                            ? String.format("[%s,%s]", lnglatSelect.getString("latitude"), lnglatSelect.getString("longitude")) : lnglatSelect.getString("address"));
                }
            } else if ("checkbox".equals(xObj.getString("componentKey"))) {
                ResponseModel checkboxResult = this.getApiResult(visualParams.getJSONObject("api"), null);
                if (!ValidationUtil.isEmpty(checkboxResult) && checkboxResult.getStatus() == 200 && !ValidationUtil.isEmpty(value)) {
                    List<Object> collect = ((JSONArray) checkboxResult.getResult()).stream().filter(y -> ((JSONArray) value).contains(JsonValueUtils.getValueByKey(y, "valueKey", "valueKey"))).collect(Collectors.toList());
                    String nameKey = collect.stream().map(item -> ((JSONObject) item).getString("nameKey")).collect(Collectors.joining("、"));
                    jsonObject.put("value", nameKey);
                }
            } else if ("select".equals(xObj.getString("componentKey"))) {
                ResponseModel selectResult = this.getApiResult(visualParams.getJSONObject("api"), null);
                if (!ValidationUtil.isEmpty(selectResult) && selectResult.getStatus() == 200 && !ValidationUtil.isEmpty(value)) {
                    ((JSONArray) selectResult.getResult()).stream().filter(y -> value.equals(JsonValueUtils.getValueByKey(y, "valueKey", "valueKey"))).findFirst().ifPresent(z -> {
                        jsonObject.put("value", ((JSONObject) z).getString("nameKey"));
                    });
                }
            }
        }
        if (!("upload".equals(xObj.getString("componentKey")) || "attachmentUpload".equals(xObj.getString("componentKey")))){
            datas.add(jsonObject);
        }
        return datas;
    }

    public JSONObject buildSubFormData(JSONObject map, int i, JSONObject yObj, Object apiResult) {
        JSONArray subs = map.getJSONArray("subs");
        JSONArray children = yObj.getJSONArray("children");

        JSONObject subObj = new JSONObject();
        subObj.put("key", "key" + i);
        subObj.put("displayName", JsonValueUtils.getValueByKey(yObj, "visualParams", "visualParams.label"));
        subObj.put("renderType", "table");

        List<Object> noHiddenChildren = children.stream().filter(x -> {
            JSONObject xObj = (JSONObject) x;
            return !"hidden".equals(JsonValueUtils.getValueByKey(xObj, "visualParams", "visualParams.behavior"));
        }).collect(Collectors.toList());

        List<JSONObject> columns = noHiddenChildren.stream().map(x -> {
            JSONObject xObj = (JSONObject) x;
            JSONObject visualParams = xObj.getJSONObject("visualParams");
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("key", xObj.get("eid"));
            jsonObject.put("dataIndex", visualParams.get("fieldKey"));
            jsonObject.put("title", visualParams.get("label"));
            return jsonObject;
        }).collect(Collectors.toList());

        subObj.put("rowKey", "key");
        subObj.put("showPage", false);
        subObj.put("columns", columns);
        JSONObject result = JSONObject.parseObject(apiResult.toString());
        subObj.put("dataList", result.get(JsonValueUtils.getValueByKey(yObj, "visualParams", "visualParams.fieldKey")));

        subs.add(subObj);
        return map;
    }

    public ResponseModel getApiResult(JSONObject apiObj, String resultConvert) {
        String url = apiObj.getString("apiPath");
        String reqType = !ValidationUtil.isEmpty(apiObj.getString("httpMethod")) ? apiObj.getString("httpMethod") : "GET";
        Object params = apiObj.get("params");
        if (ValidationUtil.isEmpty(params) && !ValidationUtil.isEmpty(apiObj.get("queryParams"))){
            JSONObject queryParam = new JSONObject();
            JSONArray queryParams = apiObj.getJSONArray("queryParams");
            queryParams.stream().forEach(x -> {
                JSONObject xObj = (JSONObject) x;
                if ("staticValue".equals(JsonValueUtils.getValueByKey(x, "value", "value.source"))){
                    queryParam.put(xObj.getString("name"), xObj.getJSONObject("value").getString("value"));
                }
            });
            if (!ValidationUtil.isEmpty(queryParam)){
                params = queryParam;
            }
        }
        Object body = apiObj.get("body");
        ResponseEntity<String> responseEntity = null;
        //如果url以/开头，则调用本服务内接口
        if (url != null && url.trim().startsWith("/")) {
            url = "http://" + GATEWAY_SERVER_NAME + url;
        }
        if (url != null && url.trim().startsWith("http")) {
            String reqUrl = buildUrl(url, params);

            HttpHeaders httpHeaders = this.builderHeaders();
            log.info("调用第三方接口: {}, httpheaders: {}", reqUrl, httpHeaders);
            try {
                URI reqUri = new URI(reqUrl);
                if (StringUtils.contrastLowerStr("GET", reqType)) {
                    responseEntity = reqUrl.contains(GATEWAY_SERVER_NAME)
                            ? RestTemplateUtils.get(restTemplate, reqUri, httpHeaders, body, String.class, new HashMap<>())
                            : RestTemplateUtils.get(reqUri, httpHeaders, body, String.class, new HashMap<>());
                } else if (StringUtils.contrastLowerStr("POST", reqType)) {
                    responseEntity = reqUrl.contains(GATEWAY_SERVER_NAME)
                            ? RestTemplateUtils.post(restTemplate, reqUri, httpHeaders, body, String.class, new HashMap<>())
                            : RestTemplateUtils.post(reqUri, httpHeaders, body, String.class, new HashMap<>());
                } else if (StringUtils.contrastLowerStr("PUT", reqType)) {
                    responseEntity = reqUrl.contains(GATEWAY_SERVER_NAME)
                            ? RestTemplateUtils.put(restTemplate, reqUri, httpHeaders, body, String.class)
                            : RestTemplateUtils.put(reqUri, httpHeaders, body, String.class);
                } else if (StringUtils.contrastLowerStr("DELETE", reqType)) {
                    responseEntity = reqUrl.contains(GATEWAY_SERVER_NAME)
                            ? RestTemplateUtils.delete(restTemplate, reqUri, httpHeaders, body, String.class)
                            : RestTemplateUtils.delete(reqUri, httpHeaders, body, String.class);
                }
            } catch (Exception e) {
                log.info("调用第三方接口失败, 请求头参数：{}", httpHeaders);
                e.printStackTrace();
                throw new RuntimeException(String.format("调用第三方接口失败, %s请求【%s】，失败原因：%s", reqType, reqUrl, e.getMessage()));
            }
        } else {
            throw new IllegalArgumentException("仅支持以/或http开头的地址");
        }
        String response = responseEntity.getBody();
        //结果转换（执行javaScript函数）
        Object bizResult = convertResult(JSONObject.parseObject(response), resultConvert);
        ResponseModel responseModel = JSONObject.parseObject(response, ResponseModel.class);

        if (200 != responseModel.getStatus()){
            log.info("调用第三方接口失败, 请求地址：{}", apiObj);
        }

        JSONObject ruleData = apiObj.getJSONObject("ruleData");
        if (!ValidationUtil.isEmpty(ruleData)) {
            String responseSuccess = ruleData.getString("responseSuccess").replace("data", "");
            Object result = JsonValueUtils.getValueByKey(bizResult, "result", responseSuccess);
            boolean isRefactor = false; // 是否需要重构返回字段
            if (result instanceof JSONObject) {
                Map<String, Object> resultMap = (Map) result;
                for (String key : ruleData.keySet()) {
                    if (!(key.equals("responseExpression") || key.equals("responseSuccess") || key.equals("responseError"))) {
                        isRefactor = true;
                        resultMap.put(key, resultMap.get(ruleData.get(key)));
                    }
                }
                result = isRefactor ? resultMap : result;
            } else if (result instanceof JSONArray) {
                JSONArray jsonArray = (JSONArray) result;

                for (int i = 0; i < jsonArray.size(); i++) {
                    JSONObject obj = jsonArray.getJSONObject(i);
                    for (String key : ruleData.keySet()) {
                        if (!(key.equals("responseExpression") || key.equals("responseSuccess") || key.equals("responseError"))) {
                            isRefactor = true;
                            obj.put(key, obj.get(ruleData.get(key)));
                        }
                    }
                }
                result = isRefactor ? jsonArray : result;
            }
            responseModel.setResult(result);
        }
        return responseModel;
    }

    private String buildUrl(String url, Object params) {
        if (!url.contains("?") && !ValidationUtil.isEmpty(params)) {
            url += "?";
        }
        if (params instanceof Map) {
            url = url + StringUtils.transMap2UrlParam((Map) params);
        } else if (params instanceof List) {
            url = url + StringUtils.transList2UrlParam((List) params);
        }
        return url.replace("?&", "?");
    }

    private HttpHeaders builderHeaders() {
        HttpHeaders httpheaders = new HttpHeaders();
        httpheaders.add("appKey", RequestContext.getAppKey());
        httpheaders.add("product", RequestContext.getProduct());
        httpheaders.add("token", RequestContext.getToken());
        httpheaders.setContentType(MediaType.APPLICATION_JSON);
        return httpheaders;
    }

    /**
     * ScriptObjectMirror 转 JavaObject
     *
     * @param scriptObj
     * @return
     */
    private static Object convertIntoJavaObject(Object scriptObj) {
        if (scriptObj instanceof ScriptObjectMirror) {
            ScriptObjectMirror scriptObjectMirror = (ScriptObjectMirror) scriptObj;
            if (scriptObjectMirror.isFunction()) {
                return scriptObjectMirror.toString();
            } else if (scriptObjectMirror.isArray()) {
                return new JSONArray(scriptObjectMirror.values().stream().map(e -> convertIntoJavaObject(e)).collect(Collectors.toList()));
            } else {
                return new JSONObject(scriptObjectMirror.entrySet().stream().collect(Collectors.toMap(e -> e.getKey(), e -> convertIntoJavaObject(e.getValue()))));
            }
        } else {
            return scriptObj;
        }
    }

    /**
     * 结果转换（执行javaScript函数）
     *
     * @param bizResult     原始请求结果
     * @param resultConvert js转换脚本
     * @return 转换后的结果
     */
    private Object convertResult(Object bizResult, String resultConvert) {
        if (!ValidationUtil.isEmpty(resultConvert)) {
            //获取javaScript执行引擎
            ScriptEngine engine = new ScriptEngineManager().getEngineByName("javascript");
            //获取js函数执行体并拼接函数名
            String jsFun = "function resultConvert(data){" + resultConvert + "}";
            //向js函数传入参数
            engine.put("data", bizResult);

            try {
                engine.eval(jsFun);
                if (engine instanceof Invocable) {
                    Invocable invoke = (Invocable) engine;
                    //执行js函数，获取返回值
                    bizResult = invoke.invokeFunction("resultConvert", bizResult);
                }
            } catch (Exception e) {
                log.info("js表达式runtime错误：{}", e.getMessage());
                throw new RuntimeException(String.format("结果转换错误【%s】", e.getMessage()));
            }
            //ScriptObjectMirror 转 JavaObject
            bizResult = convertIntoJavaObject(bizResult);
        }
        return bizResult;
    }
}
