package quant.rich;

import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.graalvm.polyglot.*;

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;

import io.micrometer.core.instrument.util.IOUtils;
import quant.rich.emoney.entity.config.SmartViewWriter;
import quant.rich.emoney.pojo.dto.IndexDetail;
import quant.rich.emoney.pojo.dto.NonParamsIndexDetail;
import quant.rich.emoney.util.SmartResourceResolver;


public class TestIndexJsMatch {
    
    private static final ObjectMapper MAPPER = new ObjectMapper();
    private static final SmartViewWriter writer = new SmartViewWriter();
    

    static {
        MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    }
    
    public static void main(String[] args) throws IOException {
        //String script = Files.readString(Path.of("./conf/extra/indexJs.js"), StandardCharsets.UTF_8);
        
        String script = IOUtils.toString(SmartResourceResolver.loadResource("./conf/extra/indexJs.js"), StandardCharsets.UTF_8);
        
        /** 一般来说如果要匹配，只会匹配出一个，但是为了保险起见还是做一个 List 来存储 */
        
        List<ArrayNode> arrays = extractValidArrays(script);
        for (ArrayNode array : arrays) {
            System.out.println("✔ 匹配数组，共 " + array.size() + " 个对象");
            for (JsonNode obj : array) {
                System.out.println(obj.toPrettyString());
                if (!obj.has("nameCode")) continue;
                String nameCode = obj.get("nameCode").asText();
                // 载入已有本地文件填充 original 字段
                String path = "./conf/extra/indexDetail/nonParams/" + nameCode + ".json";
                InputStream stream = SmartResourceResolver.loadResource(path);
                NonParamsIndexDetail detail = MAPPER.readValue(stream, NonParamsIndexDetail.class);
                detail.setOriginal(obj.toString());
                
                String joString = MAPPER.writerWithView(IndexDetail.class).writeValueAsString(detail);
                SmartResourceResolver.saveText(path, joString);
            }
        }
    }
    
    // 提取所有合法的 [...] 结构，支持嵌套匹配
    public static List<String> extractAllArrays(String text) {
        List<String> result = new ArrayList<>();

        /**
         * 这个正则表达式看起来复杂，实际上简单：
         * 1. 欲匹配对象是一个 Array，所以最外层必包含 \[...\]
         * 2. 内容是若干 Object，所以会是 (\{...\},?)+
         * 3. 每个 Object 内可能包含以下几项：
         *      3.1. id，可选数字，故为 (id:\d+,?)?
         *      3.2. data，Object 数组, 包含:
         *          3.2.1. title，字符串，故为 title:".*?",?
         *          3.2.2. items，字符串数组，故为 items:\[(".*?",?)+],?
         *          3.2.3. image，可选字符串，故为 image:".*?",?
         *          3.2.4. 组合后即为 data:\[\{(title:".*?",?|items:\[(".*?",?)+],?|image:".*?",?)+\}\],?
         *      3.3. name，字符串，故为 name:".*?",?
         *      3.4. nameCode，数字型字符串，故为 nameCode:"\d+",?
         *      3.5. 组合后即为 (\{(id:\d+,?|data:\[\{(title:".*?",?|items:\[(".*?",?)+],?|image:".*?",?)+\}+\],?|name:".*?",?|nameCode:"\d+",?)+\},?)+
         *  4. 组合上述所有即为 \[(\{(id:\d+,?|data:\[\{(title:".*?",?|items:\[(".*?",?)+],?|image:".*?",?)+\}+\],?|name:".*?",?|nameCode:"\d+",?)+\},?)+\]
         *  5. 将 ".*?" 替换为 "[^"\\]*(?:\\.[^"\\]*)*?" 以防止字符串中带双引号导致的异常截断，image 除外
         */
        Pattern p = Pattern.compile("\\[(\\{(id:\\d+,?|data:\\[\\{(title:\"[^\"\\\\]*(?:\\\\.[^\"\\\\]*)*?\",?|items:\\[(\"[^\"\\\\]*(?:\\\\.[^\"\\\\]*)*?\",?)+],?|image:\".*?\",?)+\\}+\\],?|name:\"[^\"\\\\]*(?:\\\\.[^\"\\\\]*)*?\",?|nameCode:\"\\d+\",?)+\\},?)+\\]", Pattern.DOTALL);
        Matcher m = p.matcher(text);
        
        while (m.find()) {
            result.add(m.group());
        }
        
        return result;
    }
    
    // 使用 GraalVM 的 JS 引擎尝试 JSON.stringify
    public static Optional<String> stringifyJsArray(String jsArrayText) {
        try (Context context = Context.create("js")) {
            Value result = context.eval("js", "JSON.stringify(" + jsArrayText + ")");
            return result.isString() ? Optional.of(result.asString()) : Optional.empty();
        } catch (Exception e) {
            return Optional.empty();
        }
    }
    
    // 判断某个对象是否结构匹配
    public static boolean matches(JsonNode obj) {
        return obj.has("name") &&
               obj.has("nameCode") &&
               obj.has("data") &&
               obj.get("data").isArray();
    }
    
    // 主处理逻辑
    public static List<ArrayNode> extractValidArrays(String jsSource) {
        List<ArrayNode> valid = new ArrayList<>();
        for (String raw : extractAllArrays(jsSource)) {
            stringifyJsArray(raw).ifPresent(json -> {
                try {
                    JsonNode root = MAPPER.readTree(json);
                    if (root.isArray()) {
                        ArrayNode array = (ArrayNode) root;
                        for (JsonNode obj : array) {
                            if (obj.isObject() && matches(obj)) {
                                valid.add(array);
                                break;
                            }
                        }
                    }
                } catch (Exception ignored) {
                }
            });
        }
        return valid;
    }

}
