package com.yd.oss.service.service.impl;

import com.aliyun.oss.HttpMethod;
import com.aliyun.oss.OSS;
import com.aliyun.oss.model.GeneratePresignedUrlRequest;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yd.oss.service.dto.FileProdDto;
import com.yd.oss.service.service.*;
import com.yd.oss.service.utils.PdfUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.xwpf.usermodel.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;
import java.io.*;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * PDF实现类 - 使用PdfUtil实现Word到PDF转换
 */
@Service
@Primary
@Slf4j
public class PdfServiceImpl<T> implements PdfService<T> {

    @Autowired
    private IFileTemplateService iFileTemplateService;

    @Autowired
    private FieldValueProvider<T> fieldValueProvider;

    @Autowired
    private OSS ossClient; // 注入OSS客户端

    /**
     * 根据入参的数据和文件模板的JSON字段映射构建生成PDF
     * @param dataObject
     * @param objectId
     * @param templateType
     * @return
     * @throws IOException
     */
    public String generatePDF(T dataObject, String objectId, String templateType) throws IOException {
        // 获取模板信息
        FileProdDto fileProdDto = iFileTemplateService.getFileProd("", templateType);

        // 从OSS获取模板
        InputStream templateStream = iFileTemplateService.getTemplateInputStreamFromOSS(
                fileProdDto.getBucketName(), fileProdDto.getFileKey());

        // 创建临时文件
        File tempInputFile = File.createTempFile("template", ".docx");
        File tempPdfFile = File.createTempFile("filled", ".pdf");

        try {
            // 将模板保存到临时文件
            Files.copy(templateStream, tempInputFile.toPath(), StandardCopyOption.REPLACE_EXISTING);

            // 填充Word模板数据并转换为PDF
            convertWordToPdf(tempInputFile, tempPdfFile, dataObject, fileProdDto);

            // 上传到OSS
            String objectName = "insurance_schedules/" + objectId + "_" + System.currentTimeMillis() + ".pdf";
            uploadToOSS(tempPdfFile, fileProdDto.getBucketName(), objectName);

            // 生成访问URL
            return generatePresignedUrl(fileProdDto.getBucketName(), objectName);

        } finally {
            // 清理临时文件
            tempInputFile.delete();
            tempPdfFile.delete();
        }
    }

    /**
     * 处理Word模板并转换为PDF
     * @param wordFile
     * @param pdfFile
     * @param dataObject
     * @param fileProdDto
     * @throws IOException
     */
    private void convertWordToPdf(File wordFile, File pdfFile, T dataObject, FileProdDto fileProdDto)
            throws IOException {
        try {
            // 解析字段映射
            Map<String, String> fieldMapping = parseFieldMapping(fileProdDto.getFieldMapping());

            // 创建替换映射
            Map<String, Object> replacements = createReplacements(dataObject, fieldMapping);

            // 使用Apache POI处理Word文档
            XWPFDocument document = new XWPFDocument(new FileInputStream(wordFile));

            // 替换文档中的占位符
            replacePlaceholders(document, replacements);

            // 保存处理后的Word文档
            File processedWordFile = File.createTempFile("processed", ".docx");
            try (FileOutputStream out = new FileOutputStream(processedWordFile)) {
                document.write(out);
            }

            // 使用PdfUtil转换为PDF
            convertToPdf(processedWordFile, pdfFile);

            // 删除临时文件
            processedWordFile.delete();

            log.info("成功处理Word模板并转换为PDF");
        } catch (Exception e) {
            log.error("Word模板处理或PDF转换失败", e);
            throw new IOException("Word模板处理或PDF转换失败", e);
        }
    }

    /**
     * 使用PdfUtil将Word转换为PDF
     * @param wordFile
     * @param pdfFile
     */
    private void convertToPdf(File wordFile, File pdfFile) {
        // 获取当前系统名称
        String osName = System.getProperty("os.name").toLowerCase();

        if (osName.contains("win")) {
            // Windows系统
            PdfUtil.winWordToPdf(pdfFile, wordFile);
        } else if (osName.contains("nux") || osName.contains("nix")) {
            // Linux系统
            PdfUtil.linuxWordToPdf(pdfFile, wordFile);
        } else {
            throw new UnsupportedOperationException("Unsupported operating system: " + osName);
        }
    }

    /**
     * 替换Word文档中的占位符
     * @param document
     * @param replacements
     */
    private void replacePlaceholders(XWPFDocument document, Map<String, Object> replacements) {
        // 处理段落
        for (XWPFParagraph paragraph : document.getParagraphs()) {
            replaceInParagraph(paragraph, replacements);
        }

        // 处理表格
        for (XWPFTable table : document.getTables()) {
            for (XWPFTableRow row : table.getRows()) {
                for (XWPFTableCell cell : row.getTableCells()) {
                    for (XWPFParagraph paragraph : cell.getParagraphs()) {
                        replaceInParagraph(paragraph, replacements);
                    }
                }
            }
        }

        // 处理页眉
        for (XWPFHeader header : document.getHeaderList()) {
            for (XWPFParagraph paragraph : header.getParagraphs()) {
                replaceInParagraph(paragraph, replacements);
            }
        }

        // 处理页脚
        for (XWPFFooter footer : document.getFooterList()) {
            for (XWPFParagraph paragraph : footer.getParagraphs()) {
                replaceInParagraph(paragraph, replacements);
            }
        }
    }

    /**
     * 在段落中替换占位符
     * @param paragraph
     * @param replacements
     */
    private void replaceInParagraph(XWPFParagraph paragraph, Map<String, Object> replacements) {
        String text = paragraph.getText();

        // 检查段落中是否包含占位符
        if (text != null && text.contains("{{")) {
            // 使用正则表达式查找所有占位符
            Pattern pattern = Pattern.compile("\\{\\{(.*?)\\}\\}");
            Matcher matcher = pattern.matcher(text);

            while (matcher.find()) {
                String placeholder = matcher.group(0); // 完整的占位符，如 {{name}}
                String key = matcher.group(1); // 占位符键，如 name

                // 获取替换值
                Object value = replacements.get(key);
                if (value != null) {
                    text = text.replace(placeholder, value.toString());
                }
            }

            // 清除原有运行(runs)
            for (int i = paragraph.getRuns().size() - 1; i >= 0; i--) {
                paragraph.removeRun(i);
            }

            // 添加新的运行(run)包含替换后的文本
            XWPFRun run = paragraph.createRun();
            run.setText(text);
        }
    }

    /**
     * 创建替换映射
     * @param dataObject
     * @param fieldMapping
     * @return
     */
    private Map<String, Object> createReplacements(T dataObject, Map<String, String> fieldMapping) {
        Map<String, Object> replacements = new HashMap<>();

        for (Map.Entry<String, String> entry : fieldMapping.entrySet()) {
            String dataField = entry.getKey();
            String placeholder = entry.getValue(); // 如 "{{name}}"

            // 使用泛型字段值提供器获取值
            String value = fieldValueProvider.getFieldValue(dataObject, dataField);

            // 添加替换映射
            String key = placeholder.replace("{{", "").replace("}}", "");
            replacements.put(key, value != null ? value : "");
        }

        return replacements;
    }

    /**
     * 将构建好的PDF上传至OSS
     * @param file
     * @param bucketName
     * @param objectName
     * @throws IOException
     */
    private void uploadToOSS(File file, String bucketName, String objectName) throws IOException {
        ossClient.putObject(bucketName, objectName, new FileInputStream(file));
    }

    /**
     * 生成访问URL
     * @param bucketName
     * @param objectName
     * @return
     */
    private String generatePresignedUrl(String bucketName, String objectName) {
        Date expiration = new Date(System.currentTimeMillis() + 3600 * 1000);
        GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, objectName, HttpMethod.GET);
        request.setExpiration(expiration);

        URL url = ossClient.generatePresignedUrl(request);

        // 使用 split 方法以 "?" 为分隔符分割字符串
        String[] parts = url.toString().split("\\?");
        // 取问号之前的部分
        String returnUrl = parts[0];
        return returnUrl;
    }

    /**
     * 解析JSON格式的字段映射
     * @param fieldMappingJson
     * @return
     */
    private Map<String, String> parseFieldMapping(String fieldMappingJson) {
        ObjectMapper mapper = new ObjectMapper();
        try {
            return mapper.readValue(fieldMappingJson, new TypeReference<Map<String, String>>(){});
        } catch (Exception e) {
            throw new RuntimeException("Failed to parse field mapping", e);
        }
    }
}
