package com.ruoyi.gen.controller;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.deepoove.poi.XWPFTemplate;
import com.deepoove.poi.config.Configure;
import com.deepoove.poi.data.MergeCellRule;
import com.deepoove.poi.data.RowRenderData;
import com.deepoove.poi.data.Rows;
import com.deepoove.poi.data.Tables;
import com.deepoove.poi.plugin.table.HackLoopTableRenderPolicy;
import com.deepoove.poi.plugin.table.LoopRowTableRenderPolicy;
import com.deepoove.poi.util.TableTools;
import com.ruoyi.common.core.web.controller.BaseController;
import com.ruoyi.common.core.web.domain.AjaxResult;
import com.ruoyi.gen.domain.GenTableColumn;
import com.ruoyi.gen.service.IGenTableColumnService;
import com.ruoyi.gen.service.IGenTableService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.*;
import java.util.List;

import static com.ruoyi.common.core.constant.GenConstants.QUERY_EQ;
import static com.ruoyi.common.core.constant.GenConstants.QUERY_LIKE;

/**
 * 代码文档生成 操作处理
 *
 * @author ruoyi
 */
@RequestMapping("/genDoc")
@RestController
public class GenDocController extends BaseController
{
    @Autowired
    private IGenTableService genTableService;

    @Autowired
    private IGenTableColumnService genTableColumnService;

    /**
     * 生成需求文档
     */
//    @RequiresPermissions("tool:gen:list")
    @GetMapping("/requirement")
    public AjaxResult requirement()
    {
        List<Map<String, Object>> resList = new ArrayList<>();

        List<String> tableList = new ArrayList<>();
        tableList.add("适配器");
        tableList.add("基础信息");
        tableList.add("外部接入连接信息测试");
        for (String table : tableList) {
            List<GenTableColumn> genTableColumnList = genTableColumnService.selectGenInfo(table);
            Map<String, Object> map = new LinkedHashMap<>();

            List<Map<String, Object>> queryList = new ArrayList<>();
            List<Map<String, Object>> showList = new ArrayList<>();
            List<Map<String, Object>> editList = new ArrayList<>();
            int queryIndex = 1;
            int showIndex = 1;
            int editIndex = 1;
            Map<String, Object> dataMap;

            for (GenTableColumn column : genTableColumnList) {
                if(column.isQuery()) {
                    dataMap = new HashMap<>();
                    dataMap.put("index", queryIndex++);
                    if(column.getColumnComment().contains("（")) {
                        dataMap.put("remark", (column.getColumnComment().split("（")[0]));
                    } else if(column.getColumnComment().contains("(")) {
                        dataMap.put("remark", (column.getColumnComment().split("\\(")[0]));
                    } else {
                        dataMap.put("remark", (column.getColumnComment()));
                    }
                    queryList.add(dataMap);
                }
                if(column.isList()) {
                    dataMap = new HashMap<>();
                    dataMap.put("index", showIndex++);
                    if(column.getColumnComment().contains("（")) {
                        dataMap.put("remark", (column.getColumnComment().split("（")[0]));
                    } else if(column.getColumnComment().contains("(")) {
                        dataMap.put("remark", (column.getColumnComment().split("\\(")[0]));
                    } else {
                        dataMap.put("remark", (column.getColumnComment()));
                    }
                    showList.add(dataMap);
                }
                if(column.isEdit()) {
                    dataMap = new HashMap<>();
                    dataMap.put("index", editIndex++);
                    if(column.getColumnComment().contains("（")) {
                        dataMap.put("remark", (column.getColumnComment().split("（")[0]));
                    } else if(column.getColumnComment().contains("(")) {
                        dataMap.put("remark", (column.getColumnComment().split("\\(")[0]));
                    } else {
                        dataMap.put("remark", (column.getColumnComment()));
                    }
                    editList.add(dataMap);
                }
            }

            String title = genTableColumnList.get(0).getColumnName();
            map.put("title", title);
            map.put("queryList", queryList);
            map.put("showList", showList);
            map.put("editList", editList);

            resList.add(map);
        }

        HackLoopTableRenderPolicy policy = new HackLoopTableRenderPolicy(true);

        Configure config = Configure.builder()
                .bind("queryList", policy)
                .bind("showList", policy)
                .bind("editList", policy)
                .build();
        try {
            String path = GenDocController.class.getResource("/template/requirement.docx").getPath();
            File file = new File(path);
            XWPFTemplate template = XWPFTemplate.compile(file, config).render(new LinkedHashMap<String, Object>() {
                {
                    put("datas", resList);
                }
            });
            template.writeToFile("c:\\tmp\\需求生成.docx");
            template.close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return success("生成文档位置==》c:\\tmp\\需求生成.docx");
    }

    @Value("${database}")
    private String database;

    /**
     * 生成详细设计说明书
     */
//    @RequiresPermissions("tool:gen:list")


    @GetMapping("/detail")
    public AjaxResult genDetail()
    {
        System.out.println("database=" + database);
        //dzlogistics_business dzlogistics_website_business dzlogistics_dataexchange_base datax_web
        List<Map<String, Object>> resList = new ArrayList<>();

        List<String> tableList = new ArrayList<>();
        tableList.add("监管单位");
        tableList.add("保险服务");
        tableList.add("增值服务");
        tableList.add("互联成果");
        tableList.add("开放数据");
        tableList.add("场站资源");

        boolean hasList;
        boolean hasEdit;
        StringBuilder sb;
        String title;
        String dictLabel = null;
        LinkedHashMap<String,Object> resMap;
        Map dataMap;
        List<String> processDataList;
        for (String table : tableList) {
            List<Map<String, Object>> editList = new ArrayList<>();
            int editIndex = 1;

            List<GenTableColumn> genTableColumnList = genTableColumnService.selectGenInfo(table);
            if(genTableColumnList.isEmpty()) {
                System.err.println(table + "功能找不到代码生成配置");
                continue;
            }

            resMap = new LinkedHashMap<>();
            title = genTableColumnList.get(0).getColumnName();
            resMap.put("title", title);
            processDataList = new ArrayList<>();
            //查询-------------------
            for (GenTableColumn column : genTableColumnList) {
                if(column.isQuery()) {
                    //查询用户姓名文本框：精确筛选，按照输入的字段进行精确匹配。（效果同‘SELECT 字段 FROM 表 WHERE 某字段 = 条件’即可）
                    if(QUERY_EQ.equals(column.getQueryType()) && StringUtils.isEmpty(column.getDictType())) {
                        sb = new StringBuilder();
                        sb.append("查询");
                        if(column.getColumnComment().contains("（")) {
                            System.out.println(table);
                            System.out.println(column.getColumnComment());
                            sb.append(column.getColumnComment().split("（")[0]);
                        } else if(column.getColumnComment().contains("(")) {
                            sb.append(column.getColumnComment().split("\\(")[0]);
                        } else {
                            sb.append(column.getColumnComment());
                        }
                        sb.append("文本框：精确筛选，按照输入的内容进行精确匹配。");
                        processDataList.add(sb.toString());
                    } else if(QUERY_LIKE.equals(column.getQueryType())) {
                        sb = new StringBuilder();
                        sb.append("查询");
                        if(column.getColumnComment().contains("（")) {
                            sb.append(column.getColumnComment().split("（")[0]);
                        } else if(column.getColumnComment().contains("(")) {
                            sb.append(column.getColumnComment().split("\\(")[0]);
                        } else {
                            sb.append(column.getColumnComment());
                        }
                        sb.append("文本框：模糊筛选，按照输入的内容进行模糊匹配。");
                        processDataList.add(sb.toString());
                    } else if(QUERY_EQ.equals(column.getQueryType()) && StringUtils.isNotEmpty(column.getDictType())) {
                        sb = new StringBuilder();
                        sb.append("查询");
                        if(column.getColumnComment().contains("（")) {
                            sb.append(column.getColumnComment().split("（")[0]);
                        } else if(column.getColumnComment().contains("(")) {
                            sb.append(column.getColumnComment().split("\\(")[0]);
                        } else {
                            sb.append(column.getColumnComment());
                        }
                        switch (database) {
                            case "web":
                                dictLabel = genTableColumnService.selectDictLabelBase(column.getDictType());
                                break;
                            case "website":
                                dictLabel = genTableColumnService.selectDictLabelWebsite(column.getDictType());
                                break;
                            case "dzlogistics_dataexchange_base":
                                dictLabel = genTableColumnService.selectDictLabelExchange(column.getDictType());
                                break;
                            case "datax":
                                dictLabel = genTableColumnService.selectDictLabelDatax(column.getDictType());
                                break;
                        }
                        sb.append("字典下拉框：选择");
                        sb.append(dictLabel);
                        sb.append("等进行筛选。");
                        processDataList.add(sb.toString());
                    }
                }
                if(column.isEdit()) {
                    dataMap = new HashMap<>();
                    dataMap.put("index", editIndex++);
                    if(column.getColumnComment().contains("（")) {
                        dataMap.put("remark", (column.getColumnComment().split("（")[0]));
                    } else if(column.getColumnComment().contains("(")) {
                        dataMap.put("remark", (column.getColumnComment().split("\\(")[0]));
                    } else {
                        dataMap.put("remark", (column.getColumnComment()));
                    }
                    editList.add(dataMap);
                }
            }
            //-----
            processDataList.add("重置：清除所有已填入的查询条件。");
            processDataList.add("查询：下方列表按照查询条件进行筛选后显示数据。");
            //列表-------------------
            sb = new StringBuilder();
            hasList = false;
            for (GenTableColumn column : genTableColumnList) {
                //列表显示：用户姓名、用户帐号
                if(column.isList()) {
                    if(!hasList) {
                        hasList = true;
                        sb.append("列表显示：");
                    }
                    if(column.getColumnComment().contains("（")) {
                        sb.append(column.getColumnComment().split("（")[0]);
                    } else if(column.getColumnComment().contains("(")) {
                        sb.append(column.getColumnComment().split("\\(")[0]);
                    } else {
                        sb.append(column.getColumnComment());
                    }
                    sb.append("、");
                }
            }
            if(hasList) {
                sb.deleteCharAt(sb.length() - 1);
                sb.append("。");
                processDataList.add(sb.toString());
            }
            //------
            processDataList.add("查询列表中，点击编辑按钮：进入该" + title+ "的编辑界面。");
            processDataList.add("查询列表中，点击删除按钮：删除该" + title+ "，需要二次提示是否删除。");
            processDataList.add("新增页面中，点击取消按钮：取消新增操作并返回到" + title+ "列表。");
            processDataList.add("新增页面中，点击确定按钮：新建该" + title+ "（图：新增" + title+ "）。");
            // 编辑-------------------
            sb = new StringBuilder();
            hasEdit = false;
            for (GenTableColumn column : genTableColumnList) {
                //表单项：用户姓名、用户帐号
                if(column.isEdit()) {
                    if(!hasEdit) {
                        hasEdit = true;
                        sb.append("表单项：");
                    }
                    if(column.getColumnComment().contains("（")) {
                        sb.append(column.getColumnComment().split("（")[0]);
                    } else if(column.getColumnComment().contains("(")) {
                        sb.append(column.getColumnComment().split("\\(")[0]);
                    } else {
                        sb.append(column.getColumnComment());
                    }
                    sb.append("、");
                }
            }
            if(hasEdit) {
                sb.deleteCharAt(sb.length() - 1);
                sb.append("。");
                processDataList.add(sb.toString());
            }
            resMap.put("processData", processDataList);
            resMap.put("editList", editList);

            resList.add(resMap);
        }

        HackLoopTableRenderPolicy policy = new HackLoopTableRenderPolicy(true);
        Configure config = Configure.builder()
                .bind("editList", policy)
                .build();

        String path = GenDocController.class.getResource("/template/detail.docx").getPath();
        File file = new File(path);
        try {
            XWPFTemplate template = XWPFTemplate.compile(file, config).render(new LinkedHashMap<String, Object>() {
                {
                    put("datas", resList);
                }
            });
            template.writeToFile("c:\\tmp\\详细设计.docx");
            template.close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return success("生成文档位置==》c:\\tmp\\详细设计.docx");
    }

    /**
     * 通过前端导出的层级菜单获取模板所需菜单列表及4.4能力表格数据
     * @param list 前端导出的层级菜单
     * @return 模板所需菜单列表及4.4能力表格数据
     */
    private Map<String, Object> getDataList(List<String> list) {
        Map<String, Object> resMap = new HashMap<>(2);
        List<LinkedHashMap<String, Object>> dataList = new ArrayList<>();
        List<LinkedHashMap<String, Object>> resTableList = new ArrayList<>();

        String menuName;
        String levelOneMenuName = "";
        LinkedHashMap<String, Object> levelOneMap;
        List<LinkedHashMap<String, Object>> levelTwoList = new ArrayList<>();
        LinkedHashMap<String, Object> levelTwoMap;
        String levelTwoMenuName;
        String levelThreeMenuName;
        LinkedHashMap<String, Object> resTableMap;
        int levelOneIndex = 0;
        int levelTwoIndex = 1;
        int levelThreeIndex = 1;
        LinkedHashMap<String, Object> levelTwoTableMap;
        LinkedHashMap<String, Object> levelThreeMap;
        String path;
        String pathIndex;
        for (String s : list) {
            menuName = s;
            if (!menuName.contains("--") && !menuName.contains("****")) {
                //一级菜单
                levelOneMenuName = menuName;
                // 用于2测试概要和测试3结果
                levelOneMap = new LinkedHashMap<>();
                dataList.add(levelOneMap);
                levelOneMap.put("name", menuName);
                levelTwoList = new ArrayList<>();
                // 模板中嵌套循环变量 二级菜单或三级菜单转换的二级菜单列表
                levelOneMap.put("children", levelTwoList);

                // 4.4能力
                resTableMap = new LinkedHashMap<>();
                resTableMap.put("index", ++levelOneIndex);
                resTableMap.put("name", menuName);
                // useSpringEL时内容必须有值
                setSkillDefault(resTableMap);
                resTableList.add(resTableMap);

                levelTwoIndex = 1;
            } else if (menuName.startsWith("--")) {
                //二级菜单
                levelTwoMenuName = menuName.split("--")[1];
                // 模板中嵌套循环变量的数据 二级菜单
                levelTwoMap = new LinkedHashMap<>();
                levelTwoMap.put("name", levelTwoMenuName);
                levelTwoMap.put("path", levelOneMenuName + "->" + levelTwoMenuName);
                levelTwoList.add(levelTwoMap);
                // 二级菜单 无下级
                levelTwoMap.put("level", "2");

                // 4.4能力
                resTableMap = new LinkedHashMap<>();
                resTableMap.put("index", levelOneIndex + "." + levelTwoIndex++);
                resTableMap.put("name", levelTwoMenuName);
                setSkillContent(resTableMap);
                resTableList.add(resTableMap);
                levelThreeIndex = 1;
            } else if (menuName.startsWith("****")) {
                // 三级菜单转换为二级菜单
                // 获取二级菜单生成的map，并替换为三级菜单
                // 获取上一个三级菜单
                levelTwoMap = levelTwoList.get(levelTwoList.size() - 1);
                levelTwoTableMap = resTableList.get(resTableList.size() - 1);
                levelThreeMenuName = menuName.split("\\*\\*\\*\\*")[1];
                resTableMap = new LinkedHashMap<>();
                if(levelThreeIndex == 1) {
                    // 二级菜单下循环的第一个三级菜单
                    levelTwoMap.put("level2name", levelTwoMap.get("name"));
                    levelTwoMap.put("name", levelThreeMenuName);
                    levelTwoMap.put("path", levelTwoMap.get("path") + "->" + levelThreeMenuName);
                    // 将二级菜单级别替换为三级菜单
                    levelTwoMap.put("level", "3-1");

                    // 修改原表格的二级菜单 内容置为空
                    setSkillDefault(levelTwoTableMap);

                    // 4.4能力
                    resTableMap.put("index", levelTwoTableMap.get("index") + "." + levelThreeIndex++);
                } else {
                    // 二级菜单下循环的非第一个三级菜单
                    levelThreeMap = new LinkedHashMap<>(levelTwoMap);
                    levelThreeMap.put("name", levelThreeMenuName);
                    path = (String) levelTwoMap.get("path");
                    levelThreeMap.put("path", path.substring(0, path.lastIndexOf("->")) + "->" + levelThreeMenuName);
                    // 将二级菜单级别替换为三级菜单
                    levelThreeMap.put("level", "3-2");
                    levelTwoList.add(levelThreeMap);

                    // 4.4能力
                    pathIndex = (String) levelTwoTableMap.get("index");
                    resTableMap.put("index", pathIndex.substring(0, pathIndex.lastIndexOf(".")) + "." + levelThreeIndex++);
                }
                resTableMap.put("name", levelThreeMenuName);
                // 4.4能力
                setSkillContent(resTableMap);
                resTableList.add(resTableMap);
            }
        }

        resMap.put("dataList", dataList);
        resMap.put("tableList", resTableList);
        return resMap;
    }

    private void setSkillDefault(Map<String, Object> resTableMap) {
        resTableMap.put("content", "");
        resTableMap.put("right", "");
        resTableMap.put("operate", "");
        resTableMap.put("extend", "");
    }

    private void setSkillContent(Map<String, Object> resTableMap) {
        resTableMap.put("content", "成功创建、查询、修改、删除等");
        resTableMap.put("right", "正确");
        resTableMap.put("operate", "可操作");
        resTableMap.put("extend", "可扩展");
    }

    private List<LinkedHashMap<String, Object>> genResult(List<LinkedHashMap<String, Object>> dataList, Map<String, Map<String, JSONObject>> dataMap
            ,List<LinkedHashMap<String, Object>> tableList) {

        List<LinkedHashMap<String, Object>> resList = new ArrayList<>();
        LinkedHashMap<String, Object> levelOneMap;

        String childrenTitle;
        List<LinkedHashMap<String, Object>> childrenList;
        LinkedHashMap<String, Object> childrenMap;
        JSONObject jsonObjectInsert = null;
        JSONObject jsonObjectQuery = null;
//        JSONObject clone = null;
        for (LinkedHashMap<String, Object> stringObjectLinkedHashMap : dataList) {
            levelOneMap = stringObjectLinkedHashMap;

            if (levelOneMap.get("children") != null) {
                childrenList = (List<LinkedHashMap<String, Object>>) levelOneMap.get("children");
                for (LinkedHashMap<String, Object> objectLinkedHashMap : childrenList) {
                    childrenMap = objectLinkedHashMap;
                    childrenTitle = (String) childrenMap.get("name");
                    if(dataMap.get(childrenTitle) != null) {
                        jsonObjectInsert = dataMap.get(childrenTitle).get("insert");
                        jsonObjectQuery = dataMap.get(childrenTitle).get("query");
//                        clone = jsonObjectInsert.clone();
//                        clone.remove("id");
                    }
                    if(dataMap.get(childrenTitle) != null && jsonObjectInsert.size() == 1 && jsonObjectInsert.containsKey("none") && jsonObjectInsert.get("none").equals("yes")) {
                        // 单独查询
                        childrenMap.put("level", childrenMap.get("level") + "-query");
                        childrenMap.put("query", dataMap.get(childrenTitle) != null ? getFormStr(jsonObjectQuery) : "");
                        for (LinkedHashMap<String, Object> t : tableList) {
                            if (t.get("name").equals(childrenTitle)) {
                                t.put("content", "成功查询");
                                break;
                            }
                        }
                    } else if(dataMap.get(childrenTitle) != null && jsonObjectQuery.size() == 1 && jsonObjectQuery.containsKey("none") && jsonObjectQuery.get("none").equals("yes")) {
                        // 单独插入
                        childrenMap.put("level", childrenMap.get("level") + "-insert");
                        childrenMap.put("insert", dataMap.get(childrenTitle) != null ? jsonObjectInsert : "");
                        for (LinkedHashMap<String, Object> t : tableList) {
                            if (t.get("name").equals(childrenTitle)) {
                                t.put("content", "成功创建");
                                break;
                            }
                        }
                    } else {
                        childrenMap.put("query", dataMap.get(childrenTitle) != null ? getFormStr(jsonObjectQuery) : "");
//                    childrenMap.put("insert", dataMap.get(childrenTitle) != null ? clone : "");
                        childrenMap.put("insert", dataMap.get(childrenTitle) != null ? jsonObjectInsert : "");
                        childrenMap.put("update", dataMap.get(childrenTitle) != null ? jsonObjectInsert : "");
                        childrenMap.put("deleteID", dataMap.get(childrenTitle) != null && jsonObjectInsert.get("id") != null ? jsonObjectInsert.get("id") : "");
                    }
                }
            }
            resList.add(levelOneMap);
        }
        return resList;
    }

    /**
     * 从指定文件路径读取数组数据，数组数据交替为key和json数据，并将其解析为Map对象
     * 该方法旨在处理特定格式的文件，将文件内容映射到Map中，其中键和值根据文件中的数据交替确定
     *
     * @param filePath 文件路径，用于读取数据
     * @return 返回一个Map对象，其中键为字符串，值为JSONObject对象
     */
    private static Map<String, Map<String, JSONObject>> readFileArr(String filePath) {
        // 初始化一个HashMap用于存储读取的数据
        Map<String, Map<String, JSONObject>> resMap = new HashMap<>();
        Map<String, JSONObject> dataMap = new HashMap<>();

        try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) {
            String line;
            String key = "";
            String substring;
            int index = -2;
            JSONObject jsonObject;
            // 逐行读取文件内容
            while ((line = reader.readLine()) != null) {
                index++;
                // 忽略文件的开头和结尾的[和]字符
                if("[".equals(line) || "]".equals(line)) {
                    continue;
                }

                // 对行内容进行修剪和裁剪，以去除多余的字符和引号
                substring = line.trim();
                substring = substring.substring(1, substring.length() - (substring.endsWith(",") ? 2 : 1));
                // 嵌套原始数据 "{\"sort\":0,\"viaJson\":\"[{\\\"viaName\\\":\\\"达州\\\",\\\"viaDistance\\\":\\\"20\\\"}]\",\"remark\":null}"
                // 嵌套json中替换\\\"为\\" 如{\"sort\":0,\"viaJson\":\"[{\\"viaName\\":\\"达州\\",\\"viaDistance\\":\\"20\\"}]\",\"remark\":null}
                substring = substring.replaceAll("\\\\\\\\\"", "\\\\\"");
                // 替换\"为"(包括上一步处理的嵌套json) 如{"sort":0,"viaJson":"[{\"viaName\":\"达州\",\"viaDistance\":\"20\"}]","remark":null}
                substring = substring.replaceAll("\\\\\"", "\"");
                // 根据行号的奇偶性决定是键还是值
                if(index%3 == 0) {
                    key = substring;
                    dataMap = new HashMap<>();
                } else if(index%3 == 1) {
                    // 将字符串解析为JSONObject，并放入Map中
                    jsonObject = JSONObject.parseObject(substring);
                    // 递归的将JSONObject中的文本值转换为JSON对象或数组（默认只解析外层）
                    handleTextToJson(jsonObject);
                    // 清除json中的值为null或“”的字段
                    removeNullFields(jsonObject);
                    dataMap.put("insert", jsonObject);
                } else {
                    // 将字符串解析为JSONObject，并放入Map中
                    jsonObject = JSONObject.parseObject(substring);
                    // 递归的将JSONObject中的文本值转换为JSON对象或数组（默认只解析外层）
                    handleTextToJson(jsonObject);
                    // 清除json中的值为null的字段
                    removeNullFields(jsonObject);
                    dataMap.put("query", jsonObject);
                    resMap.put(key, dataMap);
                }
            }
        } catch (IOException e) {
            // 打印异常信息
            e.printStackTrace();
        }
        // 返回填充好的Map对象
        return resMap;
    }

    /**
     * json转为表单参数
     * <p>不考虑嵌套</p>
     * @param obj json
     * @return 表单参数字符串
     */
    private String getFormStr(JSONObject obj) {
        if(obj == null) {
            return "";
        }
        StringBuilder resStr = new StringBuilder();
        for (String key : obj.keySet()) {
            resStr.append(key).append("=").append(obj.get(key)).append("&");
        }
        return resStr.substring(0, resStr.length() -1);
    }

    /**
     * 将JSONObject中的文本值转换为JSON对象或数组
     * 此方法递归遍历JSONObject，将字符串类型的JSON内容转换为相应的JSONObject或JSONArray类型
     * 这在处理从数据库或其他文本源获取的JSON数据时特别有用，其中JSON对象或数组可能被序列化为字符串
     *
     * @param jsonObj 要处理的JSONObject对象这个对象将被原地修改，不需要返回值
     */
    public static void handleTextToJson(JSONObject jsonObj) {
        // 遍历JSONObject中的每个键
        for (String key : jsonObj.keySet()) {
            try {
                // 解析当前键对应的值，以处理不同类型的值
                Object value = JSON.parse(String.valueOf(jsonObj.get(key)));
                // 如果解析后的值是字符串，则将其放回JSONObject中
                if (value instanceof String) {
                    jsonObj.put(key, value);
                } else if (value instanceof JSONObject) {
                    // 如果值是JSONObject，则递归调用handleTextToJson方法处理嵌套的JSON对象
                    JSONObject json = JSONObject.parseObject(String.valueOf(value));
                    handleTextToJson(json);
                    jsonObj.put(key, json);
                } else if (value instanceof JSONArray) {
                    // 如果值是JSONArray，则创建一个新的JSONArray，并对每个元素进行处理
                    JSONArray jsonArr = JSONArray.parseArray(String.valueOf(value));
                    JSONArray newJsonArr = new JSONArray();
                    for (Object o : jsonArr) {
                        // 如果数组元素是JSONObject，则递归处理
                        if (o instanceof JSONObject) {
                            JSONObject json = JSONObject.parseObject(String.valueOf(o));
                            handleTextToJson(json);
                            newJsonArr.add(json);
                        } else {
                            // 否则，直接添加到新的JSONArray中
                            newJsonArr.add(o);
                        }
                    }
                    jsonObj.put(key, newJsonArr);
                }
            } catch (Exception ignored) {
                // 捕获Object value = JSON.parse(String.valueOf(jsonObj.get(key)));并忽略异常，以确保处理继续进行
            }
        }
    }

    /**
     * 递归地从JSON对象或数组中移除所有为空或空字符串的字段
     * 此方法旨在清理JSON数据，确保数据的准确性和有效性
     *
     * @param obj 要清理的JSON对象或数组它可以是JSONObject或JSONArray的实例
     */
    private static void removeNullFields(Object obj) {
        // 当传入的对象是JSONObject实例时，执行清理操作
        if(obj instanceof JSONObject) {
            JSONObject jsonObj = (JSONObject) obj;
            Iterator<String> iterator = jsonObj.keySet().iterator();
            while (iterator.hasNext()) {
                String key = iterator.next();
                Object value = jsonObj.get(key);
                // 如果字段的值为null或为空字符串，则从JSONObject中移除该字段
                if (value == null || (value instanceof String && ((String) value).isEmpty())) {
                    iterator.remove();
                } else if (value instanceof JSONObject || value instanceof JSONArray) {
                    // 如果字段的值是JSONObject或JSONArray实例，则递归调用removeNullFields方法进行清理
                    removeNullFields(value);
                }
            }
        } else if (obj instanceof JSONArray) {
            // 当传入的对象是JSONArray实例时，对数组中的每个元素执行清理操作
            for (Object o : (JSONArray)obj) {
                if (o instanceof JSONObject) {
                    // 如果数组元素是JSONObject实例，则递归调用removeNullFields方法进行清理
                    removeNullFields(o);
                } else if (o instanceof JSONArray) {
                    // 如果数组元素是JSONArray实例，则对其每个元素执行清理操作
                    for (Object o1 : (JSONArray)o) {
                        removeNullFields(o1);
                    }
                }
            }
        }
    }

    @PostMapping("/genTest")
    public AjaxResult genTest(@RequestBody Map<String, List<String>> map)
    {
        String filePath = "c:/tmp/data.txt";
        Map<String, Map<String, JSONObject>> dataMap = readFileArr(filePath);

        List<String> menuList = map.get("menu");
        Map<String, Object> dataList = getDataList(menuList);
        List<LinkedHashMap<String, Object>> resList = (List<LinkedHashMap<String, Object>>)dataList.get("dataList");
        List<LinkedHashMap<String, Object>> resTableList = (List<LinkedHashMap<String, Object>>)dataList.get("tableList");

        List<LinkedHashMap<String, Object>> result = genResult(resList, dataMap, resTableList);


        LinkedHashMap<String, Object> resMap = new LinkedHashMap<>();
        resMap.put("summary", result);
        resMap.put("test", result);
        resMap.put("skill", resTableList);

        String path = Objects.requireNonNull(GenDocController.class.getResource("/template/test.docx")).getPath();
        File file = new File(path);

        LoopRowTableRenderPolicy hackLoopTableRenderPolicy  = new LoopRowTableRenderPolicy();
        Configure config = Configure.builder()
                .bind("skill", hackLoopTableRenderPolicy)
                .useSpringEL()
                .build();

        String wordPath ="c:\\tmp\\测试文档.docx";
        closeOffice(wordPath);
        try {
            // 写入文件时其实会自动递归地从JSONObject中移除所有值为null的字段
            XWPFTemplate template = XWPFTemplate.compile(file, config).render(resMap);
            template.writeToFile(wordPath);
            template.close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        openOffice(wordPath);
        return success("生成文档位置==》" + wordPath);
    }

    /**
     * 尝试打开指定文件路径上的Microsoft Office文档
     * 该方法使用ProcessBuilder来启动Microsoft Office应用程序并打开文档
     * 注意：此代码特定于安装在特定路径上的Microsoft Office版本
     *
     * @param filePath 要打开的文件的路径
     */
    public static void openOffice(String filePath) {
        try {
            // 使用 ProcessBuilder 调用 Microsoft Office
            ProcessBuilder processBuilder = new ProcessBuilder("C:\\Program Files\\Microsoft Office\\root\\Office16\\WINWORD.EXE", filePath);
            processBuilder.start();
            System.out.println("正在打开 Microsoft Office 文档: " + filePath);
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("无法打开文件: " + e.getMessage());
        }
    }

    /**
     * 尝试通过PowerShell命令关闭正在运行的Word文档
     * 此方法旨在处理在指定文件路径下运行的Word文档关闭操作
     *
     * @param filePath Word文档的完整文件路径
     */
    public static void closeOffice(String filePath) {
        try {
            // 构建PowerShell命令
            // 该命令尝试获取活动的Word应用程序实例，并查找全路径匹配的文档
            // 如果找到匹配的文档，则尝试关闭它，不保存任何更改
            String command = "powershell -Command \""
                    + "$doc = [Runtime.Interopservices.Marshal]::GetActiveObject('Word.Application').Documents | Where-Object { $_.FullName -eq '" + filePath + "' };"
                    + "if ($doc) { $doc.Close([ref]$false) }\"";

            // 执行命令
            Process process = Runtime.getRuntime().exec(command);

            // 等待命令执行完成
            int exitCode = process.waitFor();
            if (exitCode == 0) {
                System.out.println("成功关闭指定的Word文件: " + filePath);
            } else {
                System.err.println("关闭指定的Word文件失败: " + filePath);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private List<Map<String, String>> getIntegrationDataList(List<String> list) {
        List<Map<String, String>> resList = new ArrayList<>();
        Map<String, String> resMap;
        Map<String, String> levelTwoMap;
        Map<String, String> levelThreeMap;
        int index = 1;
        String module = "";
        String first = "";
        String second = "";
        String third;
        int levelThreeIndex = 1;

        for (String menuName : list) {
            if (menuName.startsWith("模块：")) {
                module = menuName.substring(3);
            } else if (!menuName.contains("--") && !menuName.contains("****")) {
                //一级菜单
                first = menuName;
            } else if (menuName.startsWith("--")) {
                // 二级菜单
                second = menuName.split("--")[1];
                resMap = new HashMap<>();
                resMap.put("index", String.valueOf(index++));
                resMap.put("module", module);
                resMap.put("first", first);
                resMap.put("second", second);
                resMap.put("third", second);
                resList.add(resMap);
                levelThreeIndex = 1;
            } else if (menuName.startsWith("****")) {
                // 三级菜单
                // 获取二级菜单生成的map
                levelTwoMap = resList.get(resList.size() - 1);
                third = menuName.split("\\*\\*\\*\\*")[1];
                if(levelThreeIndex == 1) {
                    // 二级菜单下循环的第一个三级菜单
                    //获取二级菜单生成的map,并替换third为三级菜单
                    levelTwoMap.put("third", third);
                } else {
                    // 二级菜单下循环的非第一个三级菜单
                    levelThreeMap = new HashMap<>(levelTwoMap);
                    levelThreeMap.put("third", third);
                    resList.add(levelThreeMap);
                }
                levelThreeIndex++;
            }
        }
        return resList;
    }

    @PostMapping("/genIntegrationTest")
    public AjaxResult genIntegrationTest(@RequestBody List<String> list)
    {
       /* // 合并第1行所有单元格的表格
        Map<String, String> map1 = new HashMap<>();
        map1.put("index", "1");
        map1.put("module", "门户");
        map1.put("first", "系统管理");
        map1.put("second", "菜单管理");
        map1.put("third", "删除");
        Map<String, String> map2 = new HashMap<>();
        map2.put("index", "2");
        map2.put("module", "门户");
        map2.put("first", "系统管理");
        map2.put("second", "菜单管理");
        map2.put("third", "修改");
        Map<String, String> map3 = new HashMap<>();
        map3.put("index", "3");
        map3.put("module", "门户");
        map3.put("first", "系统管理");
        map3.put("second", "菜单管理");
        map3.put("third", "新增");
        Map<String, String> map4 = new HashMap<>();
        map4.put("index", "4");
        map4.put("module", "门户");
        map4.put("first", "系统管理");
        map4.put("second", "部门管理");
        map4.put("third", "部门管理");
        ArrayList<Map<String, String>> list = new ArrayList<>();
        list.add(map1);
        list.add(map2);
        list.add(map3);
        list.add(map4);*/

        List<Map<String, String>> resList =  getIntegrationDataList(list);

        String path = Objects.requireNonNull(GenDocController.class.getResource("/template/integration_test.docx")).getPath();
        File file = new File(path);

        String wordPath ="c:\\tmp\\集成测试报告.docx";
        closeOffice(wordPath);

        MergeCellPolicy policy = new MergeCellPolicy(5, 1, 5, 1);
        Configure config = Configure.builder()
                .bind("list", policy)
                .build();
        try {

            // 写入文件时其实会自动递归地从JSONObject中移除所有值为null的字段
            XWPFTemplate template = XWPFTemplate.compile(file, config).render(
                    new HashMap<String, Object>() {{
                        put("list", resList);
                    }}
            );
            template.writeToFile(wordPath);
            template.close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        openOffice(wordPath);
        return success("生成文档位置==》" + wordPath);
    }
}
