/*
 *  Copyright (c) 2023-2026, Easy-Agents (fuhai999@gmail.com).
 *  <p>
 *  Licensed under the Apache License, Version 2.0.
 */
package com.easyagents.core.file2text.extractor.impl;

import com.easyagents.core.file2text.DocumentReadErrorCode;
import com.easyagents.core.file2text.DocumentReadException;
import com.easyagents.core.file2text.DocumentReadSupport;
import com.easyagents.core.file2text.DocumentTextSegment;
import com.easyagents.core.file2text.LightweightDocumentReadRequest;
import com.easyagents.core.file2text.LightweightDocumentReadResult;
import com.easyagents.core.file2text.extractor.FileExtractor;
import com.easyagents.core.file2text.source.DocumentSource;
import org.apache.poi.hslf.usermodel.HSLFShape;
import org.apache.poi.hslf.usermodel.HSLFSlide;
import org.apache.poi.hslf.usermodel.HSLFSlideShow;
import org.apache.poi.hslf.usermodel.HSLFTextShape;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Set;

/**
 * PowerPoint 97-2003 文档提取器。
 */
public class PptExtractor implements FileExtractor {

    private static final Set<String> MIME_TYPES = Set.of(
            "application/vnd.ms-powerpoint",
            "application/mspowerpoint",
            "application/powerpoint");

    /**
     * 判断是否支持 PPT。
     *
     * @param source 文档来源
     * @return 是否支持
     */
    @Override
    public boolean supports(DocumentSource source) {
        if (source.getMimeType() != null && MIME_TYPES.contains(source.getMimeType().toLowerCase(Locale.ROOT))) {
            return true;
        }
        String fileName = source.getFileName();
        return fileName != null && (fileName.toLowerCase(Locale.ROOT).endsWith(".ppt")
                || fileName.toLowerCase(Locale.ROOT).endsWith(".pps"));
    }

    /**
     * 提取兼容纯文本。
     *
     * @param source 文档来源
     * @return 文本
     * @throws IOException 文档 I/O 失败
     */
    @Override
    public String extractText(DocumentSource source) throws IOException {
        return read(new LightweightDocumentReadRequest(source)).getText();
    }

    /**
     * 按幻灯片读取 PPT 文本。
     *
     * @param request 读取请求
     * @return 幻灯片结构化结果
     * @throws IOException 文档 I/O 失败
     */
    @Override
    public LightweightDocumentReadResult read(LightweightDocumentReadRequest request) throws IOException {
        DocumentSource source = request.getSource();
        try (InputStream input = source.openStream();
             HSLFSlideShow slideShow = new HSLFSlideShow(input)) {
            List<HSLFSlide> slides = slideShow.getSlides();
            if (slides.size() > request.getMaxSlides()) {
                throw new DocumentReadException(DocumentReadErrorCode.DOCUMENT_STRUCTURE_LIMIT_EXCEEDED,
                        "Slide count exceeds " + request.getMaxSlides());
            }
            List<DocumentTextSegment> segments = new ArrayList<>();
            int offset = 0;
            for (int index = 0; index < slides.size(); index++) {
                request.checkCancelled();
                StringBuilder text = new StringBuilder();
                for (HSLFShape shape : slides.get(index).getShapes()) {
                    if (shape instanceof HSLFTextShape textShape) {
                        String value = textShape.getText();
                        if (value != null && !value.isBlank()) {
                            text.append(value.trim()).append('\n');
                        }
                    }
                }
                if (!text.toString().isBlank()) {
                    DocumentTextSegment segment = DocumentReadSupport.segment(
                            "slide-" + (index + 1), text.toString(), "SLIDE",
                            "第 " + (index + 1) + " 张幻灯片", offset, List.of());
                    segments.add(segment);
                    offset = segment.getEndIndex() + 1;
                }
            }
            return DocumentReadSupport.result(source, segments, request);
        } catch (DocumentReadException error) {
            throw error;
        } catch (Exception error) {
            throw new DocumentReadException(DocumentReadErrorCode.DOCUMENT_CORRUPTED,
                    "Failed to extract PPT", error);
        }
    }

    /**
     * 获取读取器优先级。
     *
     * @return 优先级
     */
    @Override
    public int getOrder() {
        return 12;
    }
}
