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

import cn.hutool.core.util.StrUtil;
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.boot.module.statistics.api.enums.DPStatusEnum;
import com.yeejoin.amos.boot.module.statistics.api.enums.MatinfoEnum;
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.beans.factory.annotation.Value;
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.util.CollectionUtils;
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.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
 * 大屏二级页面实现类
 *
 * @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;

    @Autowired
    DPSubBizServiceImpl dpSubBizService;

    @Value("${supervisionCode.prefix:https://sxtzsb.sxsei.com:19435/tzs?code=}")
    private String supervisionCodePrefix;

    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()) {
                if(!ValidationUtil.isEmpty(item.getValue())){
                    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();
            tab.put("template", template);
            this.buildContent(content, tab, param);
            // 企业且详情页签时 去掉 二维码
            if(tab.getString("key").equals("basic") && template.equals("company")){
                JSONObject map = content.getJSONObject(tab.getString("key"));
                map.put("qrcode", null);
            }
            long e = System.currentTimeMillis();
            log.info("{}tab页处理结束，共耗时：{} 毫秒", tab.get("displayName"), (e - s));
        });
        return result;
    }

    public Object aloneApi(JSONObject jsonObject){
        Object resultConvert = JsonValueUtils.getValueByKey(jsonObject, "dataConfig", "dataConfig.resultConvert");
        Object api = JsonValueUtils.getValueByKey(jsonObject, "dataConfig", "dataConfig.api");
        String renderType = jsonObject.getString("renderType");
        Object apiResult = null;
        ResponseModel responseModel = this.getApiResult((JSONObject) api, !ValidationUtil.isEmpty(resultConvert) ? resultConvert.toString() : null ,null);
        if (!ValidationUtil.isEmpty(responseModel.getResult())) {
            apiResult = responseModel.getResult();
        }else{
            apiResult = new JSONObject();
        }
        if ("timeline".equals(renderType)){
            return apiResult;
        } else if("table".equals(renderType)){
            JSONObject map = new JSONObject();
            Object columns = JsonValueUtils.getValueByKey(jsonObject, "visualParams", "visualParams.columns");
            map.put("columns", columns);
            map.put("dataList", apiResult);
            map.put("showPage", true);
            map.put("api", api);
            map.put("rowKey", JsonValueUtils.getValueByKey(jsonObject, "visualParams", "visualParams.rowKey"));
            map.put("filters", JsonValueUtils.getValueByKey(jsonObject, "visualParams", "visualParams.filters"));
            return map;
        }
        return apiResult;
    }

    public void buildContent(JSONObject content, JSONObject tab, Map<String, Object> param) {
        if (!ValidationUtil.isEmpty(tab.getBoolean("useAloneApi")) && tab.getBoolean("useAloneApi")){
            return;
        }
        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");
        JSONArray subResultParams = tab.getJSONArray("subResultParams");
        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,null);
            if (!ValidationUtil.isEmpty(responseModel.getResult())) {
                apiResult = responseModel.getResult();
                if(!CollectionUtils.isEmpty(subResultParams)){
                    for(Object subParam : subResultParams) {
                        if(StrUtil.isNotBlank(((JSONObject) apiResult).getString(subParam + ""))) {
                            String[] s1 = ((JSONObject) apiResult).getString(subParam + "").split("_");
                            if(s1.length > 1) {
                                ((JSONObject) apiResult).put(subParam + "", s1[1]);
                            }
                        }
                    }
                }
            }else{
                apiResult = new JSONObject();
            }
            long e = System.currentTimeMillis();
            log.info("{}tab页获取详情接口，共耗时：{} 毫秒", tab.get("displayName"), (e - s));
        }

        if (!tab.getString("template").contains("equip") && !tab.getString("template").contains("company") && !tab.getString("template").contains("problem")  && tab.getString("key").equals("keyinfo")){
            content.put(tab.getString("key"), JSONObject.parseObject(apiResult.toString()));
            return;
        }

        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 ("keyinfo".equals(renderType)) {
                this.buildContentKeyinfoData(tab, content, apiResult);
            } else if ("timeline".equals(renderType)){
                // 监管履历基本信息已经获取过，此次直接用
                content.put(tab.getString("key"), !ValidationUtil.isEmpty(param.get("reghistory")) ? param.get("reghistory") : 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);
            }
        }
    }

    public JSONObject buildContentKeyinfoData(JSONObject tab, JSONObject content, Object apiResult){
        JSONObject result = JSONObject.parseObject(apiResult.toString());
        JSONObject param = tab.getJSONObject("param");
        Object keyParams = JsonValueUtils.getValueByKey(content, "keyinfo", "keyinfo.keyParams");
        if (ValidationUtil.isEmpty(keyParams)){
            JSONObject keyinfo = content.getJSONObject("keyinfo");
            // 气瓶区分车用和非车用
            if ("2300".equals(param.getString("EQU_CATEGORY_CODE"))){
                keyParams = JsonValueUtils.getValueByKey(content, "keyinfo", "keyinfo.keyParams_2300_" +
                        ("1".equals(param.getString("WHETHER_VEHICLE_CYLINDER")) ? "true" : "false"));
                keyinfo.remove("keyParams_2300_true");
                keyinfo.remove("keyParams_2300_false");
            } else {
                Object selectKeyParams = JsonValueUtils.getValueByKey(content, "keyinfo", "keyinfo.keyParams_" + param.getString("EQU_CATEGORY_CODE"));
                if (!ValidationUtil.isEmpty(selectKeyParams)){
                    keyParams = selectKeyParams;
                    keyinfo.remove("keyinfo.keyParams_" + param.getString("EQU_CATEGORY_CODE"));
                } else {
                    keyParams = JsonValueUtils.getValueByKey(content, "keyinfo", "keyinfo.keyParams_default");
                }
            }
            keyinfo.remove("keyParams_default");
            keyinfo.put("keyParams", keyParams);
        }
        ((JSONArray) keyParams).stream().forEach(x -> {
            JSONObject xobj = (JSONObject) x;
            xobj.put("type", "text");
            xobj.put("value", "param".equals(xobj.getString("source")) ? param.get(xobj.getString("key")) : result.get(xobj.getString("key")));
        });
        this.processQRCodeWidget(content.getJSONObject("keyinfo").getJSONObject("qrcode"), result);

        if (tab.getString("template").contains("equip")){
            // 处理图片
            JSONArray jsonArray = result.getJSONArray("PRODUCT_PHOTO");
            if (!ValidationUtil.isEmpty(jsonArray)){
                content.getJSONObject("keyinfo").put("photo", jsonArray.getJSONObject(0).getString("url"));
            }
            // 处理标签
            JSONArray status = (JSONArray)JsonValueUtils.getValueByKey(content, "keyinfo", "keyinfo.status");
            this.processLabel(status, param.getString("EQU_STATE"));

            // 处理问题列表
            List<Map<String, String>> problem = dpSubBizService.queryProblemListBySourceId(param.getString("record"));
            List<Map<String, String>> list = new ArrayList<>();

            if (!ValidationUtil.isEmpty(problem)){
                JSONObject qrcode = (JSONObject)JsonValueUtils.getValueByKey(content, "keyinfo", "keyinfo.qrcode");
                qrcode.put("problem", problem.subList(0, 1));

                List<Map<String, String>> collect = problem.stream().map(x -> {
                    Map<String, String> map = new HashMap<>();
                    map.put("label", x.get("type"));
                    map.put("operater", x.get("descr"));
                    map.put("operatingTime", x.get("createDate"));
                    return map;
                }).collect(Collectors.toList());
                list.addAll(collect);
            }

            // 处理监管履历
            List<Map<String, String>> datas = dpSubBizService.equOnJgServiceOperationRecords(param.getString("record"));
            if (!ValidationUtil.isEmpty(datas) || !ValidationUtil.isEmpty(problem)){
                list.addAll(datas);
                param.put("reghistory", datas);
            }

            // 设备业务履历跟问题履历需要合并
            if (!ValidationUtil.isEmpty(list)){
                JSONObject infoRecords = (JSONObject)JsonValueUtils.getValueByKey(content, "keyinfo", "keyinfo.infoRecords");
                list.sort(Comparator.comparing(
                        (Map<String, String> map) -> map.get("operatingTime"),
                        Comparator.comparing(String::toString).reversed()
                ));
                infoRecords.put("datas", list);
            }
        } else if(tab.getString("template").contains("company")){
            // 处理标签
            JSONArray status = (JSONArray)JsonValueUtils.getValueByKey(content, "keyinfo", "keyinfo.status");
            this.processLabel(status, result.getString("unitType"));
            this.processLabel(status, result.getString("operatingStatus"));
            // 处理问题列表
            List<Map<String, String>> problem = dpSubBizService.queryProblemListBySourceId(param.getString("sequenceNbr"));
            if (!ValidationUtil.isEmpty(problem)){
                JSONObject qrcode = (JSONObject)JsonValueUtils.getValueByKey(content, "keyinfo", "keyinfo.qrcode");
                qrcode.put("problem", problem.subList(0, 1));
                // 企业时间轴显示问题履历
                List<Map<String, String>> list = problem.stream().map(x -> {
                    Map<String, String> map = new HashMap<>();
                    map.put("label", x.get("type"));
                    map.put("operater", x.get("descr"));
                    map.put("operatingTime", x.get("createDate"));
                    return map;
                }).sorted(Comparator.comparing(
                        (Map<String, String> map) -> map.get("operatingTime"),
                        Comparator.comparing(String::toString).reversed()
                )).collect(Collectors.toList());
                JSONObject infoRecords = (JSONObject)JsonValueUtils.getValueByKey(content, "keyinfo", "keyinfo.infoRecords");
                infoRecords.put("datas", list);
            }
            // 处理图片
            JSONArray jsonArray = result.getJSONArray("unitBusinessLicense");
            if (!ValidationUtil.isEmpty(jsonArray)){
                content.getJSONObject("keyinfo").put("photo", jsonArray.getJSONObject(0).getString("url"));
            }
        }
        return content;
    }

    private JSONArray processLabel(JSONArray status, String value){
        if (!ValidationUtil.isEmpty(value)){
            DPStatusEnum enumByStatus = DPStatusEnum.getEnumByStatus(value);
            if (!ValidationUtil.isEmpty(enumByStatus)){
                status.add(DPStatusEnum.toMap(enumByStatus));
            }
        }
        return status;
    }

    private JSONArray processShowHideRules(JSONArray children, Object showHideRules, Object apiResult) {
        JSONObject result = JSONObject.parseObject(apiResult.toString());
        Map<String,String> relationMap = new HashMap<>();
        relationMap.put("and","&&");
        relationMap.put("or","||");
        if (!ValidationUtil.isEmpty(showHideRules)) {
            ((JSONArray) showHideRules).stream().forEach(x -> {
                JSONObject xObj = (JSONObject) x;
                boolean hide = true;
                JSONArray conditions = xObj.getJSONArray("condition");
                String relation = "";
                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 (condition.equals("notUndefined")) {
                        relation += !ValidationUtil.isEmpty(fieldvalue);
                    } else if (condition.equals("unequal")) {
                        relation += !value.equals(fieldvalue);
                    } else if (condition.equals("equal")) {
                        relation += value.equals(fieldvalue);
                    } else if (condition.equals("inList")){
                        relation += value.contains(fieldvalue+"");
                    } else if (condition.equals("unList")) {
                        relation += !value.contains(fieldvalue+"");
                    }
                    relation += relationMap.getOrDefault(conditionObj.getString("relation"),"");
                }
                // 获取 JavaScript 引擎
                ScriptEngine engine = new ScriptEngineManager().getEngineByName("javascript");
                try {
                    // 将结果转换为布尔值
                    hide = !(Boolean) engine.eval(relation);
                } catch (Exception e) {
                    hide = true;
                }

                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();
        // 处理二维码
        if(!tab.getString("template").contains("company")) {
            mergedArray.stream().filter(x -> "QRCode".equals(JsonValueUtils.getValueByKey(x, "componentKey", null))).findFirst().ifPresent(x -> {
                this.processQRCodeWidget(map.getJSONObject("qrcode"), result);
            });
        }else{
            mergedArray = mergedArray.stream().filter(x -> !"QRCode".equals(JsonValueUtils.getValueByKey(x, "componentKey", null))).collect(Collectors.toList());
        }

        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()> 4 ? 4 : columnsArray.size());

        JSONArray datas = new JSONArray();
        mergedArray.stream().forEach(x -> {
            Object fieldKey = JsonValueUtils.getValueByKey(x, "visualParams", "visualParams.fieldKey");
            Object componentKey = JsonValueUtils.getValueByKey(x, "componentKey", null);
            if("tableToTable".equals(componentKey+"")){
                JSONArray children1 = (JSONArray) JsonValueUtils.getValueByKey(x, "visualParams", "visualParams.tableColumns");
                List<JSONObject> columns = children1.stream().map(t -> {
                    JSONObject xObj = (JSONObject) t;
                    JSONObject jsonObject = new JSONObject();
                    jsonObject.put("key", xObj.get("key"));
                    jsonObject.put("dataIndex", xObj.get("dataIndex"));
                    jsonObject.put("title", xObj.get("title"));
                    return jsonObject;
                }).collect(Collectors.toList());

                subObj.put("renderType", "table");
                subObj.put("displayName", JsonValueUtils.getValueByKey(x, "visualParams", "visualParams.label"));
                subObj.put("rowKey", "key");
                subObj.put("showPage", false);
                subObj.put("columns",columns);
                Object o = JSONObject.parseObject(apiResult.toString()).get(fieldKey);
                subObj.put("dataList",o);
            } else 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;
    }

    public JSONObject processQRCodeWidget(JSONObject qrcode, JSONObject result) {
        if (qrcode == null){
            return qrcode;
        }
        String problemTime = result.getString("problemTime");
        String problemStatus = result.getString("problemStatus");
        if (ValidationUtil.isEmpty(problemTime)){
            try {
                problemTime =  DateUtil.formatDate(new Date(), DateUtil.Y_M_D_HMS);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        String color = "green";
        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) || "已处理".equals(problemStatus)) {
            color = "green";
        } else if ("异常".equals(problemStatus) || "未处理".equals(problemStatus)) {
            color = "red";
        }
        // 处理隐患和企业详情码：改为固定图片。后期待定义二维码及页面内容后再改为二维码
        if (!ValidationUtil.isEmpty(qrcode.getString("picUrl"))) {
            JSONObject picUrls = qrcode.getJSONObject("picUrl");
            qrcode.put("url", picUrls.getString(color));
        }
        qrcode.put("value", !ValidationUtil.isEmpty(result.get("SUPERVISORY_CODE")) ? supervisionCodePrefix + result.get("SUPERVISORY_CODE") : result.get("USE_ORG_CODE"));
        qrcode.put("status", problemStatus);
        qrcode.put("color", color);
        return qrcode;
    }

    /**
     * 处理不同组件的展示
     *
     * @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) && !"null".equals(value)) {
                    JSONObject attachmentUploadDatasObj = new JSONObject();
                    log.info("附件数据：{}", value);
                    if(value instanceof  JSONArray){
                        ((JSONArray)value).stream().forEach(y -> {
                            JSONObject yObj = (JSONObject) y;
                            if(!ValidationUtil.isEmpty(yObj.getString("url"))) {
                                String[] str = yObj.getString("url").split("\\.");
                                if (ValidationUtil.isEmpty(str)) {
                                    yObj.put("thumb", yObj.getString("url"));
                                } else {
                                    MatinfoEnum iconUrl = MatinfoEnum.getIconUrl(str[1]);
                                    yObj.put("thumb", ValidationUtil.isEmpty(iconUrl) ? yObj.getString("url") : iconUrl.getIcon());
                                }
                            }
                        });
                    }
                    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);
                    attachmentUploadDatasObj.put("useThumb", true);
                    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(ValidationUtil.isEmpty(value)){
                    jsonObject.put("value","");
                }
            } else if ("dateTime".equals(xObj.getString("componentKey"))) {
                if (!ValidationUtil.isEmpty(value)) {
                    String f = visualParams.getString("format").replace("Y","y").replace("D","d");
                    SimpleDateFormat sdf = new SimpleDateFormat(f);
                    Date date = null;
                    try {
                        date = sdf.parse(ValidationUtil.validateString(value));
                    } catch (ParseException e) {
                        throw new RuntimeException(e);
                    }
                    jsonObject.put("value",sdf.format(date));

                }
            } else if ("checkbox".equals(xObj.getString("componentKey"))) {
                if (!ValidationUtil.isEmpty(visualParams.getJSONObject("api"))){
                    ResponseModel checkboxResult = this.getApiResult(visualParams.getJSONObject("api"), null,apiResult);
                    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"))) {
                if (!ValidationUtil.isEmpty(visualParams.getJSONObject("api")) && StrUtil.isNotEmpty(visualParams.getJSONObject("api").getString("apiPath"))){
                    ResponseModel selectResult = this.getApiResult(visualParams.getJSONObject("api"), null,apiResult);
                    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"));
                        });
                    }
                } else if(!CollectionUtils.isEmpty(visualParams.getJSONArray("data"))){
                    for(int i=0;i<visualParams.getJSONArray("data").size();i++){
                        if(visualParams.getJSONArray("data").getJSONObject(i).getString("value").equals(apiResult.getString(visualParams.getString("fieldKey")))){
                            jsonObject.put("value",visualParams.getJSONArray("data").getJSONObject(i).getString("name"));
                            break;
                        }
                    }
                }
            } else if ("radio".equals(xObj.getString("componentKey"))) {
                if (!ValidationUtil.isEmpty(visualParams.getJSONObject("api"))){
                    ResponseModel checkboxResult = this.getApiResult(visualParams.getJSONObject("api"), null,apiResult);
                    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(!ValidationUtil.isEmpty(value) && !ValidationUtil.isEmpty(visualParams.get("data"))){
                    JSONArray data = visualParams.getJSONArray("data");
                    Map<String, String> fieldMap = IntStream.range(0, data.size())
                            .mapToObj(index -> data.getJSONObject(index))
                            .collect(Collectors.toMap(
                                    json -> json.getString("value"),
                                    json -> json.getString("name")
                            ));
                    jsonObject.put("value", fieldMap.get(value));
                }
            } else if("tableToTable".equals(xObj.getString("componentKey"))){

            }
        }
        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, JSONObject detailResult) {
        String url = apiObj.getString("apiPath");
        if(ValidationUtil.isEmpty(url)){
            return null;
        }
        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"));
                }else if ("sketchProps".equals(JsonValueUtils.getValueByKey(x, "value", "value.source"))){
                    queryParam.put(xObj.getString("name"), detailResult.getString(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 = StringUtils.transMap2UrlParam(url, (Map) params);
        } else if (params instanceof List) {
            url = StringUtils.transList2UrlParam(url, (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;
    }
}
