package com.agent.management.engine;

import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * 节点输出统一包装（envelope）。
 *
 * <p>所有节点执行后，{@code NodeExecutionResult.output} 必须为本类的 {@link #toMap()} 形式：</p>
 * <pre>
 * {
 *   "status": 200,                          // 200 成功 / 400 失败
 *   "message": "调用成功",                   // 人类可读结果/失败原因
 *   "data": { "字段A": "值", "字段B": 15.83 } // 业务字段集合（严格按节点声明）
 * }
 * </pre>
 *
 * <p>后继节点通过 {@link NodeInputResolver} 从前序 envelope 的 {@code data} 字段内部取值，
 * 不再读扁平 Map 顶层。</p>
 *
 * <p>本类是不可变值对象。{@link #fromObject(Object)} 提供反向解析，
 * 用于消费端从 {@code Map<String, Object>} 还原 envelope；{@link #isEnvelope(Object)}
 * 提供 legacy 兼容判断（非 envelope 的扁平结构走旧路径）。</p>
 */
public final class NodeOutputEnvelope {

    public static final int STATUS_SUCCESS = 200;
    public static final int STATUS_FAILED = 400;

    public static final String KEY_STATUS = "status";
    public static final String KEY_MESSAGE = "message";
    public static final String KEY_DATA = "data";

    private final int status;
    private final String message;
    private final Map<String, Object> data;

    private NodeOutputEnvelope(int status, String message, Map<String, Object> data) {
        this.status = status;
        this.message = message;
        this.data = data == null ? Collections.emptyMap() : Collections.unmodifiableMap(new LinkedHashMap<>(data));
    }

    // ========== 工厂方法 ==========

    public static NodeOutputEnvelope success(String message, Map<String, Object> data) {
        return new NodeOutputEnvelope(STATUS_SUCCESS, message, data);
    }

    public static NodeOutputEnvelope failure(String message) {
        return new NodeOutputEnvelope(STATUS_FAILED, message, Collections.emptyMap());
    }

    public static NodeOutputEnvelope of(int status, String message, Map<String, Object> data) {
        return new NodeOutputEnvelope(status, message, data);
    }

    // ========== 序列化 ==========

    /**
     * 将 envelope 转为可序列化的 Map 形式（用于存入 WorkflowContext.nodeScopedOutputs）。
     */
    public Map<String, Object> toMap() {
        Map<String, Object> map = new LinkedHashMap<>(3);
        map.put(KEY_STATUS, status);
        map.put(KEY_MESSAGE, message);
        map.put(KEY_DATA, new LinkedHashMap<>(data));
        return map;
    }

    // ========== 反序列化 ==========

    /**
     * 从任意对象反序列化为 envelope。
     * 输入可以是 Map&lt;String,Object&gt; 或 NodeOutputEnvelope 本身。
     * 若输入不是 envelope 结构（{@link #isEnvelope} 返回 false），返回 null。
     */
    @SuppressWarnings("unchecked")
    public static NodeOutputEnvelope fromObject(Object raw) {
        if (raw == null) return null;
        if (raw instanceof NodeOutputEnvelope) {
            NodeOutputEnvelope other = (NodeOutputEnvelope) raw;
            return new NodeOutputEnvelope(other.status, other.message, other.data);
        }
        if (!(raw instanceof Map)) return null;
        Map<String, Object> map = (Map<String, Object>) raw;
        if (!isEnvelope(map)) return null;
        Object statusObj = map.get(KEY_STATUS);
        int status;
        if (statusObj instanceof Number) {
            status = ((Number) statusObj).intValue();
        } else if (statusObj instanceof String) {
            try { status = Integer.parseInt((String) statusObj); }
            catch (NumberFormatException e) { return null; }
        } else {
            return null;
        }
        String message = map.get(KEY_MESSAGE) == null ? "" : String.valueOf(map.get(KEY_MESSAGE));
        Object dataObj = map.get(KEY_DATA);
        Map<String, Object> data;
        if (dataObj instanceof Map) {
            data = new LinkedHashMap<>((Map<String, Object>) dataObj);
        } else {
            data = Collections.emptyMap();
        }
        return new NodeOutputEnvelope(status, message, data);
    }

    /**
     * 判断对象是否为 envelope 结构（同时含 status 与 data 字段）。
     */
    public static boolean isEnvelope(Object raw) {
        if (raw == null) return false;
        if (raw instanceof NodeOutputEnvelope) return true;
        if (!(raw instanceof Map)) return false;
        Map<?, ?> map = (Map<?, ?>) raw;
        return map.containsKey(KEY_STATUS) && map.containsKey(KEY_DATA);
    }

    // ========== Getter ==========

    public int getStatus() { return status; }

    public String getMessage() { return message; }

    public Map<String, Object> getData() { return data; }

    public boolean isSuccess() { return status == STATUS_SUCCESS; }

    public boolean isFailure() { return status == STATUS_FAILED; }
}
