package com.lingyue.parse.service;

import com.lingyue.common.exception.ServiceException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.apache.pdfbox.text.PDFTextStripper;
import org.springframework.stereotype.Service;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

/**
 * PDF文本提取服务
 * 实现分页判断逻辑：如果有文本层（文本不少）直接用，如果没有就用OCR
 * 
 * @author lingyue
 * @since 2026-01-14
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class PdfTextExtractionService {
    
    private final PaddleOcrClient paddleOcrClient;
    private final OcrResultParser ocrResultParser;
    
    /**
     * 文本阈值：每页至少需要这么多字符才认为有文本层
     */
    private static final int TEXT_THRESHOLD = 50;
    
    /**
     * 提取PDF文本（分页判断）
     * 
     * @param pdfFilePath PDF文件路径
     * @return 提取的文本内容
     */
    public String extractText(String pdfFilePath) {
        File pdfFile = new File(pdfFilePath);
        if (!pdfFile.exists()) {
            throw new ServiceException("PDF文件不存在: " + pdfFilePath);
        }
        
        List<PageTextResult> pageResults = new ArrayList<>();
        
        try (PDDocument document = org.apache.pdfbox.Loader.loadPDF(pdfFile)) {
            int totalPages = document.getNumberOfPages();
            log.info("开始处理PDF文件: {}, 总页数: {}", pdfFilePath, totalPages);
            
            PDFTextStripper textStripper = new PDFTextStripper();
            
            // 逐页处理
            for (int pageNum = 1; pageNum <= totalPages; pageNum++) {
                log.debug("处理第 {} 页/共 {} 页", pageNum, totalPages);
                
                try {
                    // 提取当前页的文本
                    textStripper.setStartPage(pageNum);
                    textStripper.setEndPage(pageNum);
                    String pageText = textStripper.getText(document);
                    
                    // 判断文本层是否足够
                    if (hasSufficientText(pageText)) {
                        // 有文本层，直接使用
                        log.debug("第 {} 页有文本层，直接使用，文本长度: {}", pageNum, pageText.length());
                        pageResults.add(new PageTextResult(pageNum, pageText, false));
                    } else {
                        // 没有文本层或文本很少，使用OCR
                        log.debug("第 {} 页文本不足，使用OCR处理，文本长度: {}", pageNum, pageText.length());
                        String ocrText = extractTextByOcr(pdfFilePath, pageNum);
                        pageResults.add(new PageTextResult(pageNum, ocrText, true));
                    }
                } catch (Exception e) {
                    log.error("处理第 {} 页时出错，尝试使用OCR", pageNum, e);
                    // 出错时也尝试OCR
                    try {
                        String ocrText = extractTextByOcr(pdfFilePath, pageNum);
                        pageResults.add(new PageTextResult(pageNum, ocrText, true));
                    } catch (Exception ocrException) {
                        log.error("第 {} 页OCR也失败", pageNum, ocrException);
                        pageResults.add(new PageTextResult(pageNum, "", true));
                    }
                }
            }
        } catch (IOException e) {
            log.error("读取PDF文件失败: {}", pdfFilePath, e);
            throw new ServiceException("读取PDF文件失败: " + e.getMessage());
        }
        
        // 合并所有页面的文本
        return combinePageTexts(pageResults);
    }
    
    /**
     * 判断文本是否足够（是否有文本层）
     * 
     * @param text 提取的文本
     * @return true表示有足够的文本层，false表示需要OCR
     */
    private boolean hasSufficientText(String text) {
        if (text == null || text.trim().isEmpty()) {
            return false;
        }
        
        // 去除空白字符后计算有效字符数
        String trimmedText = text.trim().replaceAll("\\s+", " ");
        
        // 如果有效字符数少于阈值，认为没有文本层
        return trimmedText.length() >= TEXT_THRESHOLD;
    }
    
    /**
     * 使用OCR提取指定页面的文本
     * 将PDF页面转换为图片，然后调用OCR服务
     * 
     * @param pdfFilePath PDF文件路径
     * @param pageNum 页码（从1开始，PDFBox中从0开始）
     * @return OCR识别的文本
     */
    private String extractTextByOcr(String pdfFilePath, int pageNum) {
        log.info("使用OCR处理PDF第 {} 页: {}", pageNum, pdfFilePath);
        
        File pdfFile = new File(pdfFilePath);
        File tempImageFile = null;
        
        try (PDDocument document = org.apache.pdfbox.Loader.loadPDF(pdfFile)) {
            // 1. 将PDF页面转换为图片
            PDFRenderer pdfRenderer = new PDFRenderer(document);
            BufferedImage image = pdfRenderer.renderImageWithDPI(pageNum - 1, 300); // 300 DPI
            
            // 2. 保存为临时图片文件
            String tempDir = System.getProperty("java.io.tmpdir");
            String imageFileName = "pdf_page_" + UUID.randomUUID() + "_" + pageNum + ".png";
            tempImageFile = new File(tempDir, imageFileName);
            ImageIO.write(image, "png", tempImageFile);
            log.debug("PDF第 {} 页已转换为图片: {}", pageNum, tempImageFile.getAbsolutePath());
            
            // 3. 调用OCR服务识别图片
            String ocrResult = paddleOcrClient.ocrFile(tempImageFile.getAbsolutePath());
            
            // 4. 解析OCR结果
            return parseOcrResult(ocrResult, pageNum);
        } catch (IOException e) {
            log.error("将PDF第 {} 页转换为图片失败", pageNum, e);
            throw new ServiceException("PDF页面转图片失败: " + e.getMessage());
        } catch (Exception e) {
            log.error("OCR处理PDF第 {} 页失败", pageNum, e);
            throw new ServiceException("OCR处理失败: " + e.getMessage());
        } finally {
            // 5. 清理临时图片文件
            if (tempImageFile != null && tempImageFile.exists()) {
                try {
                    Files.delete(tempImageFile.toPath());
                    log.debug("已删除临时图片文件: {}", tempImageFile.getAbsolutePath());
                } catch (IOException e) {
                    log.warn("删除临时图片文件失败: {}", tempImageFile.getAbsolutePath(), e);
                }
            }
        }
    }
    
    /**
     * 解析OCR结果
     * 使用OcrResultParser解析OCR返回的JSON
     * 
     * @param ocrResult OCR原始结果（通常是JSON格式）
     * @param pageNum 页码
     * @return 解析后的文本
     */
    private String parseOcrResult(String ocrResult, int pageNum) {
        return ocrResultParser.parseText(ocrResult);
    }
    
    /**
     * 合并所有页面的文本
     * 
     * @param pageResults 页面结果列表
     * @return 合并后的文本
     */
    private String combinePageTexts(List<PageTextResult> pageResults) {
        StringBuilder combinedText = new StringBuilder();
        
        for (PageTextResult result : pageResults) {
            if (result.getText() != null && !result.getText().trim().isEmpty()) {
                combinedText.append("=== 第 ").append(result.getPageNum()).append(" 页");
                if (result.isOcrUsed()) {
                    combinedText.append(" (OCR识别)");
                } else {
                    combinedText.append(" (文本层提取)");
                }
                combinedText.append(" ===\n");
                combinedText.append(result.getText()).append("\n\n");
            }
        }
        
        return combinedText.toString();
    }
    
    /**
     * 页面文本结果
     */
    private static class PageTextResult {
        private final int pageNum;
        private final String text;
        private final boolean ocrUsed;
        
        public PageTextResult(int pageNum, String text, boolean ocrUsed) {
            this.pageNum = pageNum;
            this.text = text;
            this.ocrUsed = ocrUsed;
        }
        
        public int getPageNum() {
            return pageNum;
        }
        
        public String getText() {
            return text;
        }
        
        public boolean isOcrUsed() {
            return ocrUsed;
        }
    }
}
