package tech.easyflow.ai.node.filegeneration;

import com.openhtmltopdf.extend.FSUriResolver;
import com.openhtmltopdf.outputdevice.helper.ExternalResourceControlPriority;
import com.openhtmltopdf.outputdevice.helper.ExternalResourceType;
import com.openhtmltopdf.pdfboxout.PdfRendererBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Component;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;

/**
 * PDF 文件渲染器。
 *
 * @author Codex
 * @since 2026-04-18
 */
@Component
public class PdfFileRenderer implements DocumentRenderer {
    static final String FONT_RESOURCE_PATH = "fonts/SourceHanSansSC-VF.ttf";
    static final String FONT_FAMILY = "EasyFlowPdfCjk";
    private static final FSUriResolver BLOCK_ALL_URI_RESOLVER = PdfFileRenderer::resolveBlockedUri;

    private final HtmlDocumentBuilder htmlDocumentBuilder;
    private final File fontFile;

    @Autowired
    public PdfFileRenderer(HtmlDocumentBuilder htmlDocumentBuilder) {
        this(htmlDocumentBuilder, FONT_RESOURCE_PATH);
    }

    PdfFileRenderer(HtmlDocumentBuilder htmlDocumentBuilder, String fontResourcePath) {
        this.htmlDocumentBuilder = htmlDocumentBuilder;
        this.fontFile = loadFont(fontResourcePath);
    }

    @Override
    public TargetFormat getTargetFormat() {
        return TargetFormat.PDF;
    }

    @Override
    public boolean supports(SourceFormat sourceFormat) {
        return sourceFormat == SourceFormat.PLAIN_TEXT
                || sourceFormat == SourceFormat.MARKDOWN
                || sourceFormat == SourceFormat.HTML;
    }

    @Override
    public FileGenerationResult render(FileGenerationRequest request) {
        String html = htmlDocumentBuilder.buildDocument(request);
        try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
            PdfRendererBuilder builder = new PdfRendererBuilder();
            builder.useFastMode();
            builder.useFont(fontFile, FONT_FAMILY);
            // 首版 PDF 只允许文本与内联样式，不允许解析任何外部或内嵌资源。
            builder.useUriResolver(BLOCK_ALL_URI_RESOLVER);
            builder.useExternalResourceAccessControl(
                    PdfFileRenderer::denyExternalResource,
                    ExternalResourceControlPriority.RUN_BEFORE_RESOLVING_URI
            );
            builder.useExternalResourceAccessControl(
                    PdfFileRenderer::denyExternalResource,
                    ExternalResourceControlPriority.RUN_AFTER_RESOLVING_URI
            );
            builder.withHtmlContent(html, fontFile.getParentFile().toURI().toString());
            builder.toStream(outputStream);
            builder.run();
            return new FileGenerationResult(
                    request.getFileName(),
                    TargetFormat.PDF.getValue(),
                    TargetFormat.PDF.getContentType(),
                    outputStream.toByteArray()
            );
        } catch (Exception e) {
            throw new IllegalStateException("PDF 导出失败: " + e.getMessage(), e);
        }
    }

    static String resolveBlockedUri(String baseUri, String uri) {
        return null;
    }

    static boolean denyExternalResource(String uri, ExternalResourceType type) {
        return false;
    }

    private File loadFont(String fontResourcePath) {
        ClassPathResource resource = new ClassPathResource(fontResourcePath);
        if (!resource.exists()) {
            throw new IllegalStateException("PDF 中文字体资源缺失: " + fontResourcePath);
        }
        try (InputStream inputStream = resource.getInputStream()) {
            Path tempFile = Files.createTempFile("easyflow-pdf-font-", ".otf");
            Files.copy(inputStream, tempFile, StandardCopyOption.REPLACE_EXISTING);
            tempFile.toFile().deleteOnExit();
            return tempFile.toFile();
        } catch (IOException e) {
            throw new IllegalStateException("PDF 中文字体资源加载失败: " + fontResourcePath, e);
        }
    }
}
