package tech.easyflow.ai.node;

import com.easyagents.flow.core.chain.Chain;
import com.easyagents.flow.core.chain.ChainDefinition;
import com.easyagents.flow.core.chain.Parameter;
import com.easyagents.flow.core.chain.repository.InMemoryChainStateRepository;
import org.junit.Assert;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.web.multipart.MultipartFile;
import tech.easyflow.ai.node.filegeneration.FileGenerationService;
import tech.easyflow.ai.node.filegeneration.MarkdownFileRenderer;
import tech.easyflow.common.filestorage.FileStorageManager;
import tech.easyflow.common.util.SpringContextUtil;

import java.lang.reflect.Field;
import java.lang.reflect.Proxy;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.UUID;

/**
 * {@link MakeFileNode} 单元测试。
 *
 * @author Codex
 * @since 2026-04-18
 */
public class MakeFileNodeTest {

    @Test
    public void testExecuteShouldReturnUrl() throws Exception {
        RecordingFileStorageManager storageManager = new RecordingFileStorageManager();
        FileGenerationService generationService = new FileGenerationService(List.of(new MarkdownFileRenderer()));
        ApplicationContext previousContext = getStaticField("applicationContext");
        Object previousBeanFactory = getStaticField("beanFactory");
        try {
            setStaticField("beanFactory", null);
            setStaticField("applicationContext", mockApplicationContext(generationService, storageManager));
            MakeFileNode node = new MakeFileNode("md", "plain_text", "测试导出", "default");
            node.setParameters(Collections.singletonList(new Parameter("content")));
            Chain chain = createChain(Map.of("content", "hello"));

            Map<String, Object> result = node.execute(chain);

            Assert.assertEquals("https://example.com/generated.md", result.get("url"));
            Assert.assertNotNull(storageManager.lastFile);
            Assert.assertEquals("测试导出.md", storageManager.lastFile.getOriginalFilename());
        } finally {
            setStaticField("applicationContext", previousContext);
            setStaticField("beanFactory", previousBeanFactory);
        }
    }

    private static Chain createChain(Map<String, Object> memory) {
        Chain chain = new Chain(new ChainDefinition(), UUID.randomUUID().toString());
        chain.setChainStateRepository(new InMemoryChainStateRepository());
        chain.getState().getMemory().putAll(memory);
        return chain;
    }

    private static ApplicationContext mockApplicationContext(FileGenerationService service,
                                                             FileStorageManager storageManager) {
        return (ApplicationContext) Proxy.newProxyInstance(
                ApplicationContext.class.getClassLoader(),
                new Class[]{ApplicationContext.class},
                (proxy, method, args) -> {
                    if ("getBean".equals(method.getName()) && args != null && args.length == 1 && args[0] instanceof Class<?> clazz) {
                        if (clazz == FileGenerationService.class) {
                            return service;
                        }
                        if (clazz == FileStorageManager.class) {
                            return storageManager;
                        }
                    }
                    if ("equals".equals(method.getName())) {
                        return proxy == args[0];
                    }
                    if ("hashCode".equals(method.getName())) {
                        return System.identityHashCode(proxy);
                    }
                    if (method.getReturnType() == boolean.class) {
                        return false;
                    }
                    if (method.getReturnType() == int.class) {
                        return 0;
                    }
                    if (method.getReturnType() == long.class) {
                        return 0L;
                    }
                    return null;
                }
        );
    }

    @SuppressWarnings("unchecked")
    private static <T> T getStaticField(String fieldName) throws Exception {
        Field field = SpringContextUtil.class.getDeclaredField(fieldName);
        field.setAccessible(true);
        return (T) field.get(null);
    }

    private static void setStaticField(String fieldName, Object value) throws Exception {
        Field field = SpringContextUtil.class.getDeclaredField(fieldName);
        field.setAccessible(true);
        field.set(null, value);
    }

    private static class RecordingFileStorageManager extends FileStorageManager {
        private MultipartFile lastFile;

        @Override
        public String save(MultipartFile file) {
            this.lastFile = file;
            return "https://example.com/generated.md";
        }
    }
}
