package tech.easyflow.ai.document.support;

import org.junit.Assert;
import org.junit.Test;
import tech.easyflow.ai.document.exception.DocumentParseBridgeException;
import tech.easyflow.ai.document.model.DocumentSourceRef;
import tech.easyflow.common.filestorage.FileStorageService;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetSocketAddress;
import java.nio.charset.StandardCharsets;
import com.sun.net.httpserver.HttpServer;

/**
 * {@link DocumentSourceLoader} 单元测试。
 *
 * @author Codex
 * @since 2026-04-14
 */
public class DocumentSourceLoaderTest {

    /**
     * 验证可从 filePath 正常读取文件内容。
     *
     * @throws IOException 测试读取异常
     */
    @Test
    public void shouldLoadContentFromFilePath() throws IOException {
        DocumentSourceLoader loader = new DocumentSourceLoader(new FakeFileStorageService("demo-pdf".getBytes(StandardCharsets.UTF_8)));
        DocumentSourceRef sourceRef = DocumentSourceRef.ofPath("/attachment/test/demo.pdf");

        LoadedDocumentSource loadedSource = loader.load(sourceRef);

        Assert.assertEquals("demo.pdf", loadedSource.getFileName());
        Assert.assertEquals(8L, loadedSource.getSize().longValue());
        Assert.assertArrayEquals("demo-pdf".getBytes(StandardCharsets.UTF_8), loadedSource.getContentBytes());
    }

    /**
     * 验证缺少有效来源时抛出明确异常。
     */
    @Test
    public void shouldThrowWhenSourceMissing() {
        DocumentSourceLoader loader = new DocumentSourceLoader(new FakeFileStorageService(new byte[0]));

        try {
            loader.load(new DocumentSourceRef());
            Assert.fail("expected DocumentParseBridgeException");
        } catch (DocumentParseBridgeException e) {
            Assert.assertEquals("unsupported_source", e.getCode());
        }
    }

    /**
     * 验证 filePath 为远端 URL 时不会误走存储读取。
     */
    @Test
    public void shouldPreferRemoteDownloadWhenFilePathIsRemoteUrl() throws IOException {
        DocumentSourceLoader loader = new DocumentSourceLoader(new FailingFileStorageService());
        HttpServer server = HttpServer.create(new InetSocketAddress(0), 0);
        byte[] body = "demo-pdf".getBytes(StandardCharsets.UTF_8);
        server.createContext("/demo.pdf", exchange -> {
            exchange.sendResponseHeaders(200, body.length);
            exchange.getResponseBody().write(body);
            exchange.close();
        });
        server.start();
        try {
            DocumentSourceRef sourceRef = new DocumentSourceRef();
            sourceRef.setFileName("demo.pdf");
            sourceRef.setFilePath("http://127.0.0.1:" + server.getAddress().getPort() + "/demo.pdf");

            LoadedDocumentSource loadedSource = loader.load(sourceRef);

            Assert.assertEquals("demo.pdf", loadedSource.getFileName());
            Assert.assertArrayEquals(body, loadedSource.getContentBytes());
        } finally {
            server.stop(0);
        }
    }

    private static class FakeFileStorageService implements FileStorageService {

        private final byte[] content;

        private FakeFileStorageService(byte[] content) {
            this.content = content;
        }

        @Override
        public String save(org.springframework.web.multipart.MultipartFile file) {
            return null;
        }

        @Override
        public void delete(String path) {
        }

        @Override
        public InputStream readStream(String path) {
            return new ByteArrayInputStream(content);
        }

        @Override
        public long getFileSize(String path) {
            return content.length;
        }
    }

    private static class FailingFileStorageService implements FileStorageService {

        @Override
        public String save(org.springframework.web.multipart.MultipartFile file) {
            return null;
        }

        @Override
        public void delete(String path) {
        }

        @Override
        public InputStream readStream(String path) throws IOException {
            throw new IOException("should not read remote url from storage");
        }

        @Override
        public long getFileSize(String path) {
            return 0L;
        }
    }
}
