package com.agent.management.engine;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;

import java.util.*;

/**
 * 节点输入变量解析器。
 *
 * <p>对节点 data.inputs[] 中的每个字段：
 * <ol>
 *   <li>优先使用显式 mapping（sourceNodeId/sourceField/sourcePath）</li>
 *   <li>若未配置或来源不可达，进入四级隐式关联 fallback：
 *       精确同名 → 忽略分隔符/大小写同名 → JSON 嵌套路径精确匹配 → JSON 嵌套路径模糊匹配</li>
 *   <li>按目标 type 做类型转换</li>
 * </ol>
 */
@Slf4j
public class NodeInputResolver {

    private static final ObjectMapper MAPPER = new ObjectMapper();

    /**
     * 解析后的输入结果。
     */
    public static class ResolvedInputs {
        private final Map<String, Object> values = new LinkedHashMap<>();
        private final List<String> missing = new ArrayList<>();
        private final List<String> warnings = new ArrayList<>();

        public Map<String, Object> getValues() {
            return values;
        }

        public List<String> getMissing() {
            return missing;
        }

        public List<String> getWarnings() {
            return warnings;
        }

        public boolean hasMissing() {
            return !missing.isEmpty();
        }
    }

    /**
     * 解析节点输入。
     *
     * @param nodeData 节点 data（JSON）
     * @param workspace 当前节点工作区
     * @return 解析结果（值、缺失项、警告）
     */
    public static ResolvedInputs resolveInputs(JsonNode nodeData, NodeWorkspace workspace) {
        ResolvedInputs result = new ResolvedInputs();
        JsonNode inputsNode = nodeData.path("inputs");
        if (!inputsNode.isArray() || inputsNode.isEmpty()) {
            return result;
        }

        for (JsonNode field : inputsNode) {
            String name = field.path("name").asText("");
            if (name.isEmpty()) {
                continue;
            }
            String type = field.path("type").asText("string");
            boolean required = field.path("required").asBoolean(false);

            Object value = resolveInputValue(name, type, field.path("mapping"), workspace, result);
            if (value == null) {
                if (required) {
                    result.missing.add(name);
                }
            } else {
                result.values.put(name, value);
            }
        }
        return result;
    }

    private static Object resolveInputValue(String name, String type, JsonNode mappingNode,
                                            NodeWorkspace workspace, ResolvedInputs result) {
        // 1. 显式 mapping
        if (mappingNode != null && !mappingNode.isMissingNode()) {
            String sourceNodeId = mappingNode.path("sourceNodeId").asText("");
            String sourceField = mappingNode.path("sourceField").asText("");
            String sourcePath = mappingNode.path("sourcePath").asText(null);
            if (!sourceNodeId.isEmpty()) {
                if (workspace.getScopedOutputs().containsKey(sourceNodeId)) {
                    if (sourceField.isEmpty()) {
                        sourceField = name;
                    }
                    Object value = workspace.getScopedOutput(sourceNodeId, sourceField);
                    if (value != null && sourcePath != null && !sourcePath.isBlank()) {
                        value = JsonPathExtractor.extract(value, sourcePath);
                    }
                    if (value != null) {
                        return VariableConverter.convert(value, type);
                    }
                    result.warnings.add(name + " 显式映射到 " + sourceNodeId + "." + sourceField
                            + (sourcePath != null ? "/" + sourcePath : "") + " 但值为空");
                } else {
                    result.warnings.add(name + " 显式映射来源 " + sourceNodeId + " 不可达，已忽略");
                }
            }
        }

        // 2. 初始输入（运行级变量，扁平形式，不涉及节点命名空间）
        Object direct = workspace.getVariable(name);
        if (direct != null) {
            return VariableConverter.convert(direct, type);
        }

        // 3. 隐式关联 fallback：按拓扑逆序（最近前驱优先）
        List<String> ordered = new ArrayList<>(workspace.getScopedOutputs().keySet());
        Collections.reverse(ordered);

        // 3.1 精确同名
        for (String nodeId : ordered) {
            Object value = workspace.getScopedOutput(nodeId, name);
            if (value != null) {
                return VariableConverter.convert(value, type);
            }
        }

        // 3.2 忽略 [-_] 与大小写同名（穿透 envelope.data）
        String normName = normalizeForMatch(name);
        for (String nodeId : ordered) {
            Map<String, Object> dataView = workspace.getScopedDataView(nodeId);
            if (dataView == null) continue;
            for (Map.Entry<String, Object> e : dataView.entrySet()) {
                if (normalizeForMatch(e.getKey()).equals(normName)) {
                    return VariableConverter.convert(e.getValue(), type);
                }
            }
        }

        // 3.3 JSON 嵌套路径精确同名：以 envelope.data 为根
        for (String nodeId : ordered) {
            Map<String, Object> dataView = workspace.getScopedDataView(nodeId);
            if (dataView == null) continue;
            Object extracted = JsonPathExtractor.extract(dataView, name);
            if (extracted != null) {
                return VariableConverter.convert(extracted, type);
            }
        }

        // 3.4 JSON 嵌套路径模糊同名：以 envelope.data 为根，忽略 [-_] 与大小写
        for (String nodeId : ordered) {
            Map<String, Object> dataView = workspace.getScopedDataView(nodeId);
            if (dataView == null) continue;
            Object extracted = extractByNormalizedPath(dataView, name);
            if (extracted != null) {
                return VariableConverter.convert(extracted, type);
            }
        }

        return null;
    }

    /**
     * 忽略 [-_] 与大小写的归一化，用于模糊匹配。
     */
    static String normalizeForMatch(String s) {
        if (s == null) return "";
        return s.replaceAll("[-_]", "").toLowerCase(Locale.ROOT);
    }

    /**
     * 按归一化路径从对象中取值：路径每一节都忽略 [-_] 与大小写匹配键名。
     */
    private static Object extractByNormalizedPath(Object root, String path) {
        if (path == null || path.isBlank()) {
            return root;
        }
        Object current = root;
        String[] segments = path.split("\\.");
        for (String segment : segments) {
            if (segment.isEmpty()) {
                continue;
            }
            current = stepFuzzy(current, segment);
            if (current == null) {
                return null;
            }
        }
        return current;
    }

    private static Object stepFuzzy(Object current, String segment) {
        String normSeg = normalizeForMatch(segment);

        if (current instanceof Map<?, ?> map) {
            // 先精确匹配，再模糊匹配
            if (map.containsKey(segment)) {
                return map.get(segment);
            }
            for (Map.Entry<?, ?> e : map.entrySet()) {
                Object key = e.getKey();
                if (key instanceof String k && normalizeForMatch(k).equals(normSeg)) {
                    return e.getValue();
                }
            }
            return null;
        }

        if (current instanceof JsonNode node) {
            if (node.isArray()) {
                Integer idx = parseIndex(segment);
                return idx != null && idx >= 0 && idx < node.size()
                        ? jsonNodeToValue(node.get(idx)) : null;
            }
            JsonNode child = node.get(segment);
            if (child != null) {
                return jsonNodeToValue(child);
            }
            for (Iterator<String> it = node.fieldNames(); it.hasNext(); ) {
                String field = it.next();
                if (normalizeForMatch(field).equals(normSeg)) {
                    return jsonNodeToValue(node.get(field));
                }
            }
            return null;
        }

        if (current instanceof Collection<?> collection) {
            Integer idx = parseIndex(segment);
            if (idx == null || idx < 0) {
                return null;
            }
            int i = 0;
            for (Object item : collection) {
                if (i == idx) {
                    return item;
                }
                i++;
            }
            return null;
        }

        // POJO：先转 JsonNode 再递归
        try {
            JsonNode node = MAPPER.valueToTree(current);
            return stepFuzzy(node, segment);
        } catch (Exception e) {
            return null;
        }
    }

    private static Integer parseIndex(String segment) {
        try {
            return Integer.parseInt(segment);
        } catch (NumberFormatException e) {
            return null;
        }
    }

    private static Object jsonNodeToValue(JsonNode node) {
        if (node == null || node.isNull()) {
            return null;
        }
        if (node.isTextual()) {
            return node.asText();
        }
        if (node.isNumber()) {
            return node.numberValue();
        }
        if (node.isBoolean()) {
            return node.booleanValue();
        }
        try {
            return MAPPER.treeToValue(node, Object.class);
        } catch (Exception e) {
            return node.toString();
        }
    }
}
