package com.agent.management.engine;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import lombok.extern.slf4j.Slf4j;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 工作流变量类型转换器。
 *
 * <p>基于 docs/design/workflow-node-fields-design.md 中梳理的规则实现，支持：
 * <ul>
 *   <li>通用基础类型转换（string/number/boolean/object/array/filePath/directoryPath）</li>
 *   <li>RAG 检索证据列表的特殊转换</li>
 *   <li>LLM 文本结果的结构化提取</li>
 * </ul>
 */
@Slf4j
public class VariableConverter {

    private static final ObjectMapper MAPPER = new ObjectMapper();

    /**
     * 将源值转换为目标类型。
     *
     * @param value      源值
     * @param targetType IOField 类型名
     * @return 转换后的值；无法转换时返回 null（调用方可根据 required 决定是否报错）
     */
    @SuppressWarnings("unchecked")
    public static Object convert(Object value, String targetType) {
        if (value == null) {
            return null;
        }
        if (targetType == null || "string".equals(targetType)) {
            return toString(value);
        }
        return switch (targetType) {
            case "number" -> toNumber(value);
            case "boolean" -> toBoolean(value);
            case "object" -> toObject(value);
            case "array" -> toArray(value);
            case "filePath", "directoryPath" -> toString(value); // 路径类型以字符串形式承载
            default -> toString(value);
        };
    }

    public static String toString(Object value) {
        if (value == null) return null;
        if (value instanceof String s) return s;
        if (value instanceof Collection<?> c) {
            try {
                return MAPPER.writeValueAsString(c);
            } catch (Exception e) {
                return c.stream().map(Object::toString).collect(Collectors.joining("\n"));
            }
        }
        if (value instanceof Map<?, ?> || isPojo(value)) {
            try {
                return MAPPER.writeValueAsString(value);
            } catch (Exception e) {
                return value.toString();
            }
        }
        return value.toString();
    }

    public static Number toNumber(Object value) {
        if (value == null) return Double.NaN;
        if (value instanceof Number n) return n;
        if (value instanceof Boolean b) return b ? 1 : 0;
        if (value instanceof Collection<?> c) return c.size();
        String s = value.toString().trim();
        if (s.isEmpty()) return Double.NaN;
        // 尝试提取第一个数字
        StringBuilder digits = new StringBuilder();
        boolean seenDot = false;
        boolean seenDigit = false;
        for (int i = 0; i < s.length(); i++) {
            char ch = s.charAt(i);
            if (ch >= '0' && ch <= '9') {
                digits.append(ch);
                seenDigit = true;
            } else if (ch == '.' && !seenDot && seenDigit) {
                digits.append(ch);
                seenDot = true;
            } else if (ch == '-' && digits.isEmpty()) {
                digits.append(ch);
            } else if (seenDigit) {
                break;
            }
        }
        if (!seenDigit) return Double.NaN;
        try {
            String numStr = digits.toString();
            if (numStr.contains(".")) {
                return Double.parseDouble(numStr);
            }
            return Long.parseLong(numStr);
        } catch (NumberFormatException e) {
            return Double.NaN;
        }
    }

    public static Boolean toBoolean(Object value) {
        if (value == null) return false;
        if (value instanceof Boolean b) return b;
        if (value instanceof Number n) return n.doubleValue() != 0;
        if (value instanceof Collection<?> c) return !c.isEmpty();
        if (value instanceof Map<?, ?> m) return !m.isEmpty();
        String s = value.toString().trim().toLowerCase(Locale.ROOT);
        return "true".equals(s) || "1".equals(s) || "yes".equals(s) || !s.isEmpty();
    }

    @SuppressWarnings("unchecked")
    public static Map<String, Object> toObject(Object value) {
        if (value == null) return null;
        if (value instanceof Map<?, ?> m) {
            return (Map<String, Object>) m;
        }
        if (value instanceof Collection<?> c) {
            Iterator<?> it = c.iterator();
            if (it.hasNext()) {
                Object first = it.next();
                if (first instanceof Map<?, ?>) {
                    return (Map<String, Object>) first;
                }
            }
            return Map.of("items", new ArrayList<>(c));
        }
        String s = toString(value);
        if (s != null && !s.isEmpty()) {
            try {
                Object parsed = MAPPER.readValue(s, Object.class);
                if (parsed instanceof Map) return (Map<String, Object>) parsed;
                return Map.of("value", parsed);
            } catch (Exception ignored) {
                return Map.of("value", s);
            }
        }
        return Map.of("value", value);
    }

    @SuppressWarnings("unchecked")
    public static List<Object> toArray(Object value) {
        if (value == null) return Collections.emptyList();
        if (value instanceof Collection<?> c) {
            return new ArrayList<>(c);
        }
        if (value.getClass().isArray()) {
            int len = java.lang.reflect.Array.getLength(value);
            List<Object> list = new ArrayList<>(len);
            for (int i = 0; i < len; i++) {
                list.add(java.lang.reflect.Array.get(value, i));
            }
            return list;
        }
        String s = toString(value);
        if (s != null && !s.isEmpty()) {
            try {
                Object parsed = MAPPER.readValue(s, Object.class);
                if (parsed instanceof Collection) return new ArrayList<>((Collection<?>) parsed);
                if (parsed instanceof Map) return List.of(parsed);
                return List.of(parsed);
            } catch (Exception ignored) {
                return Arrays.asList(s.split("\r?\n"));
            }
        }
        return List.of(value);
    }

    /**
     * 将 POJO 转换为 Map，用于把 RagEvidence 等对象注入 object/array 目标类型。
     */
    @SuppressWarnings("unchecked")
    public static Map<String, Object> pojoToMap(Object pojo) {
        if (pojo == null) return null;
        if (pojo instanceof Map<?, ?> m) return (Map<String, Object>) m;
        try {
            ObjectNode node = MAPPER.valueToTree(pojo);
            return MAPPER.convertValue(node, Map.class);
        } catch (Exception e) {
            log.warn("[VariableConverter] POJO 转 Map 失败: {}", e.getMessage());
            return Map.of("value", pojo.toString());
        }
    }

    /**
     * 判断对象是否为普通 POJO（非 JDK 集合/Map/基本类型）。
     */
    private static boolean isPojo(Object value) {
        return !(value instanceof String || value instanceof Number || value instanceof Boolean
                || value instanceof Collection || value instanceof Map || value.getClass().isArray());
    }
}
