package tech.easyflow.ai.easyagentsflow.repository;

import com.easyagents.flow.core.chain.ChainDefinition;
import com.easyagents.flow.core.chain.Node;
import com.easyagents.flow.core.chain.Parameter;
import com.easyagents.flow.core.node.BaseNode;
import com.easyagents.flow.core.node.EndNode;
import com.easyagents.flow.core.node.HttpNode;
import com.easyagents.flow.core.node.LlmNode;
import com.easyagents.flow.core.node.LoopNode;
import com.easyagents.flow.core.node.StartNode;
import org.junit.Assert;
import org.junit.Test;
import tech.easyflow.ai.node.ConditionNode;
import tech.easyflow.ai.node.DocNode;
import tech.easyflow.ai.node.DownloadNode;
import tech.easyflow.ai.node.MakeFileNode;
import tech.easyflow.ai.node.PluginToolNode;
import tech.easyflow.ai.node.SaveDatasetNode;
import tech.easyflow.ai.node.SearchDatasetNode;
import tech.easyflow.ai.node.WorkflowNode;
import tech.easyflow.datacenter.execution.model.DatasetRef;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamClass;
import java.util.List;

/**
 * 工作流定义快照 Java 序列化兼容约束测试。
 */
public class ChainDefinitionSnapshotSerializationTest {

    /**
     * 验证全部运行时业务节点对象图可完成定义快照往返。
     *
     * @throws Exception 序列化失败时抛出
     */
    @Test
    public void shouldRoundTripAllRuntimeNodeTypes()
            throws Exception {
        ChainDefinition definition = new ChainDefinition();
        definition.setId("snapshot-all-node-types");
        List<Node> nodes = List.of(
                node(new StartNode(), "start"),
                node(new EndNode(), "end"),
                node(new HttpNode(), "http"),
                node(new LlmNode(), "llm"),
                node(new LoopNode(), "loop"),
                node(new PluginToolNode(), "plugin"),
                node(new DownloadNode(), "download"),
                node(new WorkflowNode(), "workflow"),
                node(new DocNode(), "doc"),
                datasetNode(new SearchDatasetNode(), "search"),
                datasetNode(new SaveDatasetNode(), "save"),
                conditionNode(),
                node(new MakeFileNode(), "make-file"));
        nodes.forEach(definition::addNode);

        byte[] bytes;
        try (ByteArrayOutputStream output =
                     new ByteArrayOutputStream();
             ObjectOutputStream objectOutput =
                     new ObjectOutputStream(output)) {
            objectOutput.writeObject(definition);
            objectOutput.flush();
            bytes = output.toByteArray();
        }
        ChainDefinition restored;
        try (ObjectInputStream input =
                     new ObjectInputStream(
                             new ByteArrayInputStream(bytes))) {
            restored = (ChainDefinition) input.readObject();
        }

        Assert.assertEquals(
                definition.getId(), restored.getId());
        Assert.assertEquals(
                nodes.size(), restored.getNodes().size());
    }

    /**
     * 验证定义对象图关键类使用显式稳定 UID，防止新增方法导致默认 UID 漂移。
     */
    @Test
    public void shouldKeepStableSerialVersionUids() {
        List<Class<?>> stableTypes = List.of(
                Node.class,
                BaseNode.class,
                Parameter.class,
                StartNode.class,
                EndNode.class,
                HttpNode.class,
                LlmNode.class,
                LoopNode.class,
                PluginToolNode.class,
                DownloadNode.class,
                WorkflowNode.class,
                DocNode.class,
                SearchDatasetNode.class,
                SaveDatasetNode.class,
                ConditionNode.class,
                ConditionNode.ConditionBranch.class,
                ConditionNode.ConditionRule.class,
                MakeFileNode.class,
                DatasetRef.class);
        for (Class<?> type : stableTypes) {
            Assert.assertEquals(
                    "unstable serialVersionUID: "
                            + type.getName(),
                    1L,
                    ObjectStreamClass.lookup(type)
                            .getSerialVersionUID());
        }
    }

    /**
     * 设置测试节点 ID。
     *
     * @param node 节点
     * @param id 节点 ID
     * @return 原节点
     */
    private <T extends Node> T node(T node, String id) {
        node.setId(id);
        return node;
    }

    /**
     * 设置带数据集引用的节点。
     *
     * @param node 数据集节点
     * @param id 节点 ID
     * @return 原节点
     */
    private <T extends Node> T datasetNode(
            T node, String id) {
        DatasetRef ref = new DatasetRef();
        ref.setTableName("dataset_table");
        if (node instanceof SearchDatasetNode) {
            ((SearchDatasetNode) node).setDatasetRef(ref);
        } else {
            ((SaveDatasetNode) node).setDatasetRef(ref);
        }
        return node(node, id);
    }

    /**
     * 创建带完整嵌套规则对象图的条件节点。
     *
     * @return 条件节点
     */
    private ConditionNode conditionNode() {
        ConditionNode.ConditionRule rule =
                new ConditionNode.ConditionRule();
        rule.setId("rule");
        ConditionNode.ConditionBranch branch =
                new ConditionNode.ConditionBranch();
        branch.setId("branch");
        branch.setRules(List.of(rule));
        ConditionNode node = node(
                new ConditionNode(), "condition");
        node.setBranches(List.of(branch));
        return node;
    }
}
