package com.easyagents.document.pptx.mineru;

import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.easyagents.document.core.async.DocumentAsyncTaskManager;
import com.easyagents.document.core.async.InMemoryDocumentAsyncTaskRepository;
import com.easyagents.document.core.mineru.MineruClient;
import com.easyagents.document.core.mineru.MineruMapper;
import com.easyagents.document.core.mineru.MineruProperties;
import com.easyagents.document.core.mineru.MineruResultPayload;
import com.easyagents.document.core.entity.ParseFile;
import com.easyagents.document.core.entity.ParseResponse;
import com.easyagents.document.core.entity.ParseResult;
import com.easyagents.document.core.entity.ParseTaskInfo;
import com.easyagents.document.core.entity.ParseTaskStatus;
import com.easyagents.document.core.entity.PptxParseRequest;
import org.apache.poi.xslf.usermodel.XMLSlideShow;
import org.apache.poi.xslf.usermodel.XSLFSlide;
import org.apache.poi.xslf.usermodel.XSLFTextBox;
import org.junit.Assert;
import org.junit.Test;

import java.awt.Rectangle;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.concurrent.Executor;

/**
 * PPTX MinerU 服务测试。
 *
 * @author Codex
 * @since 2026-04-16
 */
public class MineruPptxDocumentParseServiceTest {

    @Test
    public void shouldBuildMarkdownAndImagesForSlides() throws IOException {
        RecordingClient client = new RecordingClient(defaultProperties());
        MineruMapper mapper = new MineruMapper(defaultProperties());
        MineruPptxDocumentParseService service = new MineruPptxDocumentParseService(
            defaultProperties(),
            client,
            mapper,
            new DocumentAsyncTaskManager(new InMemoryDocumentAsyncTaskRepository(), directExecutor())
        );

        PptxParseRequest request = new PptxParseRequest();
        request.addFile(ParseFile.of("demo.pptx", buildPptxBytes()));

        ParseResponse response = service.parse(request);

        Assert.assertEquals(1, response.getResults().size());
        ParseResult result = response.getResults().get(0);
        Assert.assertTrue(result.getMarkdown().contains("# Slide 1"));
        Assert.assertTrue(result.getMarkdown().contains("images/slide-001/page.png"));
        Assert.assertTrue(result.getMarkdown().contains("slide-ocr-1"));
        Assert.assertEquals(2, result.getImages().size());
        Assert.assertNotNull(result.getImages().get(0).getContent());
        Assert.assertNotNull(result.getArtifacts().getExtraJsonArtifacts().get("pptx"));
    }

    @Test
    public void shouldSupportAsyncTaskFlow() throws IOException {
        RecordingClient client = new RecordingClient(defaultProperties());
        MineruMapper mapper = new MineruMapper(defaultProperties());
        MineruPptxDocumentParseService service = new MineruPptxDocumentParseService(
            defaultProperties(),
            client,
            mapper,
            new DocumentAsyncTaskManager(new InMemoryDocumentAsyncTaskRepository(), directExecutor())
        );

        PptxParseRequest request = new PptxParseRequest();
        request.addFile(ParseFile.of("demo.pptx", buildPptxBytes()));

        ParseTaskStatus status = service.submit(request);
        ParseTaskInfo taskInfo = service.queryTaskInfo(status.getTaskId());

        Assert.assertEquals("completed", taskInfo.getStatus());
        Assert.assertNotNull(taskInfo.getResult());
        Assert.assertEquals(1, taskInfo.getResult().getResults().size());
    }

    @Test
    public void shouldSupportStringifiedMineruSlideArtifacts() throws IOException {
        RecordingClient client = new RecordingClient(defaultProperties(), true);
        MineruMapper mapper = new MineruMapper(defaultProperties());
        MineruPptxDocumentParseService service = new MineruPptxDocumentParseService(
            defaultProperties(),
            client,
            mapper,
            new DocumentAsyncTaskManager(new InMemoryDocumentAsyncTaskRepository(), directExecutor())
        );

        PptxParseRequest request = new PptxParseRequest();
        request.addFile(ParseFile.of("demo.pptx", buildPptxBytes()));

        ParseResponse response = service.parse(request);

        Assert.assertEquals(1, response.getResults().size());
        ParseResult result = response.getResults().get(0);
        Assert.assertTrue(result.getMarkdown().contains("slide-ocr-1"));
        Assert.assertFalse(result.getBlocks().isEmpty());
        Assert.assertEquals(2, result.getImages().size());
    }

    private byte[] buildPptxBytes() throws IOException {
        XMLSlideShow slideShow = new XMLSlideShow();
        slideShow.setPageSize(new java.awt.Dimension(640, 360));
        createSlide(slideShow, "第一页");
        createSlide(slideShow, "第二页");
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        slideShow.write(outputStream);
        slideShow.close();
        return outputStream.toByteArray();
    }

    private void createSlide(XMLSlideShow slideShow, String text) {
        XSLFSlide slide = slideShow.createSlide();
        XSLFTextBox textBox = slide.createTextBox();
        textBox.setAnchor(new Rectangle(20, 20, 300, 80));
        textBox.setText(text);
    }

    private MineruProperties defaultProperties() {
        MineruProperties properties = new MineruProperties();
        properties.setBaseUrl("http://127.0.0.1:8000");
        return properties;
    }

    private Executor directExecutor() {
        return new Executor() {
            @Override
            public void execute(Runnable command) {
                command.run();
            }
        };
    }

    private static class RecordingClient extends MineruClient {

        private int parseCount;
        private final boolean stringifyArtifacts;

        private RecordingClient(MineruProperties properties) {
            this(properties, false);
        }

        private RecordingClient(MineruProperties properties, boolean stringifyArtifacts) {
            super(properties, new MineruMapper(properties));
            this.stringifyArtifacts = stringifyArtifacts;
        }

        @Override
        public MineruResultPayload parse(com.easyagents.document.core.entity.ParseRequest request) {
            parseCount++;
            return new MineruMapper(testProperties()).toResultPayload(syncPayload(parseCount));
        }

        private JSONObject syncPayload(int index) {
            JSONObject payload = new JSONObject();
            payload.put("backend", "vlm-http-client");
            payload.put("version", "3.0.9");
            JSONObject result = new JSONObject();
            result.put("md_content", "slide-ocr-" + index);
            result.put("middle_json", stringifyArtifacts ? middleJson().toJSONString() : middleJson());
            result.put("content_list", stringifyArtifacts ? contentList(index).toJSONString() : contentList(index));
            JSONObject results = new JSONObject();
            results.put("slide-" + index, stringifyArtifacts ? result.toJSONString() : result);
            payload.put("results", results);
            return payload;
        }

        private JSONObject middleJson() {
            JSONObject middleJson = new JSONObject();
            middleJson.put("_backend", "vlm-http-client");
            middleJson.put("_version_name", "3.0.9");
            middleJson.put("pdf_info", new JSONArray());
            return middleJson;
        }

        private JSONArray contentList(int index) {
            JSONArray contentList = new JSONArray();
            JSONObject text = new JSONObject();
            text.put("type", "text");
            text.put("text", "slide-ocr-" + index);
            text.put("page_idx", 0);
            text.put("bbox", new JSONArray());
            contentList.add(text);
            return contentList;
        }

        private static MineruProperties testProperties() {
            MineruProperties properties = new MineruProperties();
            properties.setBaseUrl("http://127.0.0.1:8000");
            return properties;
        }
    }
}
