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.model.OssProvider;
import com.yd.oss.service.service.*;
import com.yd.oss.service.utils.OssUtils;
import com.yd.oss.service.utils.PdfUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
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 OssUtils ossUtils;

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

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

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

        // 创建临时文件
        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 = "";
            //项目类型
            String projectType = ossUtils.getProjectType(provider.getProjectBizId());
            projectType = StringUtils.isNotBlank(projectType) ? projectType : "pc";
            //环境变量
            String env = ossUtils.getActiveEnv();
            env = StringUtils.isNotBlank(env) ? env : "prod";
            String prefix = projectType + "/" + env + "/";
            if (StringUtils.isNotBlank(customFileName)) {
                objectName = prefix + "insurance_schedules/" + System.currentTimeMillis() + "/" + customFileName + ".pdf";
            }else {
                objectName = prefix + "insurance_schedules/" + objectId + "_" + System.currentTimeMillis() + ".pdf";
            }

            uploadToOSS(tempPdfFile, fileProdDto.getBucketName(), objectName,provider,ossClient);

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

        } 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));

            // 修复：确保中文字体正确处理
            ensureChineseFontSupport(document);

            // 替换文档中的占位符
            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);
        }
    }

    /**
     * 确保中文字体支持
     */
    private void ensureChineseFontSupport(XWPFDocument document) {
        // 设置文档默认字体为支持中文的字体
        for (XWPFParagraph paragraph : document.getParagraphs()) {
            for (XWPFRun run : paragraph.getRuns()) {
                // 设置中文字体
                run.setFontFamily("Microsoft YaHei"); // 微软雅黑
                // 或者使用其他支持中文的字体
                // run.setFontFamily("SimSun"); // 宋体
                // run.setFontFamily("SimHei"); // 黑体
            }
        }

        // 处理表格中的字体
        for (XWPFTable table : document.getTables()) {
            for (XWPFTableRow row : table.getRows()) {
                for (XWPFTableCell cell : row.getTableCells()) {
                    for (XWPFParagraph paragraph : cell.getParagraphs()) {
                        for (XWPFRun run : paragraph.getRuns()) {
                            run.setFontFamily("Microsoft YaHei");
                        }
                    }
                }
            }
        }
    }

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

        log.info("开始PDF转换 - 源文件: {}, 目标文件: {}, 系统: {}",
                wordFile.getAbsolutePath(), pdfFile.getAbsolutePath(), osName);

        // 记录源文件内容信息用于调试
        try {
            String sourceContentPreview = getWordContentPreview(wordFile);
            log.info("源文件内容预览: {}", sourceContentPreview);
        } catch (Exception e) {
            log.warn("无法获取源文件内容预览: {}", e.getMessage());
        }

        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);
        }

        // 验证转换结果
        if (pdfFile.exists() && pdfFile.length() > 0) {
            log.info("PDF转换成功! 文件: {}, 大小: {} bytes",
                    pdfFile.getAbsolutePath(), pdfFile.length());
        } else {
            throw new RuntimeException("PDF转换失败，目标文件不存在或为空: " + pdfFile.getAbsolutePath());
        }
    }

    /**
     * 获取Word文件内容预览（用于调试）
     */
    private String getWordContentPreview(File wordFile) throws IOException {
        try (XWPFDocument doc = new XWPFDocument(new FileInputStream(wordFile))) {
            StringBuilder content = new StringBuilder();

            // 获取前3个段落的前100个字符
            int paragraphCount = 0;
            for (XWPFParagraph p : doc.getParagraphs()) {
                if (paragraphCount >= 3) break;
                String text = p.getText();
                if (text != null && !text.trim().isEmpty()) {
                    content.append(text.substring(0, Math.min(text.length(), 100))).append("... ");
                    paragraphCount++;
                }
            }

            return content.toString();
        }
    }

    /**
     * 替换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,OssProvider provider, OSS ossClient) throws IOException {
        ossClient.putObject(bucketName, objectName, new FileInputStream(file));
    }

    /**
     * 生成访问URL
     * @param bucketName
     * @param objectName
     * @return
     */
    private String generatePresignedUrl(String bucketName, String objectName,OssProvider provider, OSS ossClient) {
        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];
        returnUrl = returnUrl.replace("http","https");
        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);
        }
    }
}
