package com.sdtool.common.tool;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONWriter;
import com.alibaba.fastjson2.TypeReference;
import com.google.common.base.Splitter;
import com.sweetfish.service.RetResult;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Created by jlutt on 2021-03-23
 *
 * @author jlutt
 */
public final class GroovyVariableParser {

    private final Logger logger = LogManager.getLogger(this.getClass().getSimpleName());

    static Pattern blockPattern = Pattern.compile("\\[\\s*([\\s.\\-\\S]+)\\b(.*)]");

    private String variableName = null;

    private List<String> variableLines = null;

    private List<GroovyVariableItem> variableItemList = new ArrayList<>();

    public GroovyVariableParser() {
    }

    public static String substr(String line, int startIndex) {
        if (startIndex >= line.length()) return "";

        return line.substring(startIndex).trim();
    }

    /**
     * 参数解析
     * 2024-04-19尝试用groovy的ASTBuilder SourceUnit等解析代码获取变量，都要保证代码可编译，性能不知道是不是代码不能编译导致不是很高，暂时搁置，还是用现有的文本解析方式
     * @param fileName 文件名
     */
    public List<GroovyVariableItem> parse(String fileName) {

        try {
            String scriptContent = FileUtils.readFileToString(FileUtils.getFile(fileName), StandardCharsets.UTF_8);
            Iterable<String> lines = Splitter.on('\n').trimResults().split(scriptContent);

            boolean beginVariable = false;

            int lineNo = 0;
            for (String line : lines) {
                ++lineNo;

                line = line.trim();
                if (line.isEmpty()) {
                    continue;
                }

                if (line.startsWith("//")) {
                    line = StringUtils.deleteWhitespace(line);

                    if (line.toLowerCase().startsWith("//vbegin")) {
                        beginVariable = true;
                        continue;
                    }

                    if (line.toLowerCase().startsWith("//vend")) {
                        break;
                    }
                }

                if (beginVariable) {
                    if (line.startsWith("//")) {
                        String cleanLine = substr(line, "//".length());
                        Matcher matcher = blockPattern.matcher(cleanLine);
                        if (matcher.matches()) {
                            //处理上一次的数据
                            parsePreviousBlock();

                            variableName = matcher.group(1);
                            variableLines = new ArrayList<>();

                            continue;
                        }
                    }

                    if (StringUtils.isBlank(variableName)) {
                        continue;
                    }
                    variableLines.add(line);
                }
            }

            parsePreviousBlock();

            return variableItemList;
        } catch (IOException e) {
            logger.error(e.getMessage(), e);
            return null;
        }
    }

    public RetResult<List<Map<String, String>>> parseTableParam(String appHome, String columns, String jsonName, long supplierCode) {
        String jsonFile = appHome + File.separator +
                "conf" + File.separator +
                "script" + File.separator +
                supplierCode + File.separator +
                "quoteFiles" + File.separator +
                jsonName;
        try {
            if (Files.exists(Paths.get(jsonFile))) {
                String scriptContent = FileUtils.readFileToString(FileUtils.getFile(jsonFile), StandardCharsets.UTF_8);

                List<Map<String, String>> mapList = JSON.parseObject(scriptContent, new TypeReference<List<Map<String, String>>>() {
                });
                if (StringUtils.isNotEmpty(columns)) {
                    mapList = sortMap(mapList, columns);
                }
                return RetResult.<List<Map<String, String>>>successT().result(mapList);
            } else {
                return RetResult.<List<Map<String, String>>>successT().result(new ArrayList<>());
            }
        } catch (IOException e) {
            return RetResult.<List<Map<String, String>>>errorT().retinfo(e.getMessage());
        }
    }

    /**
     * 参数修改
     *
     * @param fileName       文件名
     * @param updateItemList 参数列表
     */
    public void update(String fileName, List<GroovyVariableItem> updateItemList) {
        try {
            String scriptContent = FileUtils.readFileToString(FileUtils.getFile(fileName), StandardCharsets.UTF_8);
            for (GroovyVariableItem item : updateItemList) {
                if (item.getVariableKind() == 0) {
                    //表格参数的单独处理表格，不再这里处理
                    //这里针对字符串参数有问题，没加引号。。。得实际做一个字符串参数看看
                    if (item.getOrginDefine().contains("\"")) {
                        scriptContent = scriptContent.replace(item.getOrginDefine(), item.getVariableId() + " = \"" + item.getVariableValue() + "\"");
                    } else {
                        scriptContent = scriptContent.replace(item.getOrginDefine(), item.getVariableId() + " = " + item.getVariableValue());
                    }
                }
            }

            Files.write(Paths.get(fileName),
                    Collections.singleton(new StringBuilder(scriptContent)),
                    StandardCharsets.UTF_8,
                    StandardOpenOption.CREATE,
                    StandardOpenOption.WRITE,
                    StandardOpenOption.TRUNCATE_EXISTING);
        } catch (IOException e) {
            logger.error(e.getMessage(), e);
        }
    }

    public RetResult<String> updateTableParam(List<Map<String, String>> jsonContent, String columns, String appHome, String jsonName, long supplierCode) {
        String jsonFile = appHome + File.separator +
                "conf" + File.separator +
                "script" + File.separator +
                supplierCode + File.separator +
                "quoteFiles" + File.separator +
                jsonName;

        List<Map<String, String>> sortMapList = sortMap(jsonContent, columns);
        try {
            FileUtils.writeStringToFile(FileUtils.getFile(jsonFile),
                    JSON.toJSONString(sortMapList, JSONWriter.Feature.PrettyFormat, JSONWriter.Feature.MapSortField),
                    StandardCharsets.UTF_8);
            return RetResult.successT();
        } catch (IOException e) {
            logger.error(e.getMessage(), e);
            return RetResult.<String>errorT().retinfo(e.getMessage());
        }
    }

    /**
     * 从excel文件导入表格参数，写入到指定的json文件中
     *
     * @param fileName     excel文件
     * @param columns      列（暂时未用到，直接用excel的列名和顺序）
     * @param appHome      运行本目录
     * @param jsonName     表格名
     * @param supplierCode 分库
     * @return 操作信息
     */
    public RetResult<String> importTableParam(String fileName, String columns, String appHome, String jsonName, long supplierCode) {
        //通过excel文件导入表格参数，由于需要无类型的读，所以使用通用的格式Map<String, String>读取数据

        //此类表格都不会很大，无所谓缓存了，直接读完事
        EasyExcel.read(fileName, new AnalysisEventListener<Map<Integer, String>>() {
            private Map<Integer, String> headMap;

            private final List<Map<String, String>> dataList = new ArrayList<>();

            @Override
            public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
                this.headMap = headMap;
                System.out.println("表头信息:" + headMap);
            }

            @Override
            public void invoke(Map<Integer, String> data, AnalysisContext analysisContext) {
                //把表头和值放入Map
                //使用LinkedHashMap的目的是让最终的数据按照excel列的顺序来
                HashMap<String, String> paramsMap = new LinkedHashMap<>();
                for (int i = 0; i < data.size(); i++) {
                    String key = headMap.get(i);
                    String value = data.get(i);
                    //将表头作为map的key，每行每个单元格的数据作为map的value
                    paramsMap.put(key, value);
                }
                dataList.add(paramsMap);
                System.out.println("解析到一条数据:" + JSON.toJSONString(data));
            }

            @Override
            public void doAfterAllAnalysed(AnalysisContext analysisContext) {
                System.out.println("全部数据读取完毕");
                System.out.println("全部数据:" + JSON.toJSONString(dataList));

                //和调用updateTableParam函数有些许不同，就几行代码，不重构公共函数了
                String jsonFile = appHome + File.separator +
                        "conf" + File.separator +
                        "script" + File.separator +
                        supplierCode + File.separator +
                        "quoteFiles" + File.separator +
                        jsonName;

                try {
                    FileUtils.writeStringToFile(FileUtils.getFile(jsonFile),
                            JSON.toJSONString(dataList, JSONWriter.Feature.PrettyFormat, JSONWriter.Feature.MapSortField),
                            StandardCharsets.UTF_8);
                } catch (IOException e) {
                    logger.error(e.getMessage(), e);
                }
            }
        }).sheet().headRowNumber(1).doRead();


        return RetResult.successT();
    }

    private void parsePreviousBlock() {
        if ((StringUtils.isNotBlank(variableName)) && (variableLines != null) && (!variableLines.isEmpty())) {

            GroovyVariableItem variableItem = new GroovyVariableItem();
            variableItem.setVariableKind(0);
            if (variableName.contains(".")) {
                //这里的表格参数的变量只定义一个文件名，方便前端获取和修改，表格实际参数应该放在vEnd之后，在start里面初始化，
                //现在为了统一，把表格参数统一为json对象数组，查找的都根据条件在数组中查找
                variableItem.setVariableKind(1);
                variableItem.setVariableName(variableName.split("\\.")[0]);
                variableItem.setColumnNames(StringUtils.deleteWhitespace(variableName.split("\\.")[1]));
            } else {
                variableItem.setVariableName(variableName);
                variableItem.setColumnNames("");
            }

            for (String variableLine : variableLines) {
                variableLine = variableLine.trim();
                if (variableLine.isEmpty()) {
                    continue;
                }
                if (variableLine.startsWith("//")) {
                    continue;
                }
                //解析参数
                String variableId = variableLine.split("=")[0].trim();
                String variableValue = variableLine.split("=")[1].split(";")[0].trim();

                if (variableValue.contains("QuoteTable(")) {
                    //懒得用正则表达式了
                    variableValue = variableValue.replaceAll(" ", "")
                            .replaceAll("\\{newQuoteTable\\(sysAppHome,sysSupplierCode,", "")
                            .replaceAll("\\)\\}\\(\\)", "");
                }
                //如果是字符串，需要去掉引号
                variableValue = variableValue.replaceAll("\"", "");


                variableItem.setVariableId(variableId);
                variableItem.setVariableValue(variableValue);

                variableItem.setOrginDefine(variableLine);
                //有多行数据只取第一行
                break;
            }

            this.variableItemList.add(variableItem);

            variableName = null;
            variableLines = null;
        }
    }

    private static List<Map<String, String>> sortMap(List<Map<String, String>> list, String columns) {
        String[] keys = columns.split(",");
        List<Map<String, String>> sortedList = new ArrayList<>();
        for (Map<String, String> map : list) {
            //这里为了顺序，必须使用LinkedHashMap
            Map<String, String> sortedMap = new LinkedHashMap<>();
            for (String key : keys) {
                sortedMap.put(key, map.get(key));
            }
            sortedList.add(sortedMap);
        }
        return sortedList;
    }

    private static void parseVariableDefinition(String comment, String variableDefinition) {
        // 匹配简单变量定义的正则表达式
        Pattern simplePattern = Pattern.compile("(\\w+)\\s+(\\w+)\\s*=\\s*(.+)");
        Matcher simpleMatcher = simplePattern.matcher(variableDefinition);
        if (simpleMatcher.find()) {
            String type = simpleMatcher.group(1);
            String param = simpleMatcher.group(2);
            String value = simpleMatcher.group(3);

            System.out.println("Name: " + comment);
            System.out.println("Parameter: " + param);
            System.out.println("Value: " + value);
            return;
        }

        // 匹配复杂变量定义的正则表达式
        Pattern complexPattern = Pattern.compile("(@\\w+\\s+)?def\\s+(\\w+)\\s*=\\s*\\{.*?\"(.*?)\".*?\\}");
        Matcher complexMatcher = complexPattern.matcher(variableDefinition);
        if (complexMatcher.find()) {
            String modifier = complexMatcher.group(1) != null ? complexMatcher.group(1).trim() : "";
            String param = complexMatcher.group(2);
            String value = complexMatcher.group(3);

            System.out.println("Name: " + comment);
            System.out.println("Parameter: " + param);
            System.out.println("Value: " + value);
        } else {
            System.out.println("Unable to parse variable definition: " + variableDefinition);
        }
    }

    public static void main(String[] args) {
//        String script = "//vbegin\n" +
//                "//[印工]\n" +
//                "double printMoney = 1.123\n" +
//                "//[白卡纸250克平方价.长,宽,500张,1000张,2000张,3000张,5000张,10000张]\n" +
//                "@Lazy def 白卡纸250克平方价表 = { new QuoteTable(sysAppHome, sysSupplierCode, \"白卡纸250克平方价表.json\") }()\n" +
//                "//[白卡纸350克平方价.长,宽,500,1000,2000,3000,5000,10000]\n" +
//                "@Lazy def 白卡纸350克平方价表 = {new QuoteTable(sysAppHome, sysSupplierCode, \"白卡纸350克平方价表.json\"\n" +
//                "                , [\"长\", \"宽\"],\n" +
//                "                [\n" +
//                "                        \"500\"  : \"0-500\",\n" +
//                "                        \"1000\" : \"500-1000\",\n" +
//                "                        \"2000\" : \"1000-2000\",\n" +
//                "                        \"3000\" : \"2000-3000\",\n" +
//                "                        \"5000\" : \"3000-5000\",\n" +
//                "                        \"10000\": \"5000-10000\"\n" +
//                "                ],\n" +
//                "                \"数量\",\n" +
//                "                \"平方价\"\n" +
//                "        )\n" +
//                "    }()\n" +
//                "//vend";
//
//        // 提取vbegin和vend之间的内容
//        Pattern pattern = Pattern.compile("//vbegin(.*?)//vend", Pattern.DOTALL);
//        Matcher matcher = pattern.matcher(script);
//        if (matcher.find()) {
//            String variablesSection = matcher.group(1);
//            System.out.println("Variables Section:\n" + variablesSection);
//
//            // 提取注释和变量定义
//            Pattern varPattern = Pattern.compile("//\\[(.*?)]\\s*([^/]+)");
//            Matcher varMatcher = varPattern.matcher(variablesSection);
//            while (varMatcher.find()) {
//                String comment = varMatcher.group(1);
//                String variableDefinition = varMatcher.group(2).trim();
//                System.out.println("Comment: " + comment);
//                System.out.println("Variable Definition: " + variableDefinition);
//
//                // 解析变量定义
//                parseVariableDefinition(comment, variableDefinition);
//            }
//        } else {
//            System.out.println("No variables found between vbegin and vend.");
//        }
        String input = """
                @Lazy\s
                def 白卡纸350克平方价表 = {new QuoteTable(sysAppHome, sysSupplierCode, "白卡纸350克平方价表.json"
                                , ["长", "宽"],
                                [
                                        "500"  : "0-500",
                                        "1000" : "500-1000",
                                        "2000" : "1000-2000",
                                        "3000" : "2000-3000",
                                        "5000" : "3000-5000",
                                        "10000": "5000-10000"
                                ],
                                "数量",
                                "平方价"
                        )
                    }()
                """;

        // 提取文件名（不带扩展名）
        Pattern pattern1 = Pattern.compile("(?<=def\\s)[^\",{}\\s]+");
        Matcher matcher1 = pattern1.matcher(input);
        if (matcher1.find()) {
            System.out.println("文件名（不带扩展名）: " + matcher1.group());
        }

        // 提取完整文件名（包括扩展名）
        Pattern pattern2 = Pattern.compile("([^\",{}]+)\\.json");
        Matcher matcher2 = pattern2.matcher(input);
        if (matcher2.find()) {
            System.out.println("完整文件名（包括扩展名）: " + matcher2.group());
        }



//        GroovyVariableParser variableParser = new GroovyVariableParser();
//        List<GroovyVariableItem> itemList = variableParser.parse("D:\\Work\\BE_QuoteScript_2.groovy");
//        if (itemList != null) {
//            for (GroovyVariableItem item : itemList) {
//                System.out.println(item.toString());
//            }
//        }
//
//        RetResult<List<Map<String, String>>> test = variableParser.parseTableParam("D:\\Work\\dnyAggloERP",  "","testTable.json", 1000L);
//        System.out.println(JSON.toJSONString(test));
//
//        variableParser.importTableParam("D:\\11111.xls", "", "D:\\Work\\dnyAggloERP", "testTable2.json", 1000L);
////        List<Map<String, String>> rest = test.getResult();
////        rest.add(Utility.ofMap(
////                "联数", "二联", "印色", "单面单黑边联相同", "单价", "8.8", "规格", "大度", "开数", "8开"
////        ));
////        variableParser.updateTableParam(rest, "规格,联数,开数,印色,单价", "D:\\Work\\dnyAggloERP", "testTable.json", 1000L);
    }
}
