package com.njcn.gather.tools.report.util;

import lombok.extern.slf4j.Slf4j;
import org.docx4j.openpackaging.parts.WordprocessingML.MainDocumentPart;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.Map;

/**
 * 占位符处理工具类
 * 
 * @author hongawen
 * @version 1.0
 * {@code @data} 2025/9/5 10:30
 */
@Slf4j
public class PlaceholderUtil {


    /**
     * 批量替换占位符
     * 优先尝试一次性批量替换，失败时降级为逐个替换
     *
     * @param mainDocumentPart 主文档部分
     * @param placeholderMap 占位符映射表（原始格式，会自动预处理）
     */
    public static void replaceAllPlaceholders(MainDocumentPart mainDocumentPart, Map<String, String> placeholderMap) {
        if (mainDocumentPart == null || placeholderMap == null || placeholderMap.isEmpty()) {
            log.warn("文档部分或占位符映射为空，跳过替换操作");
            return;
        }
        // 预处理占位符映射
        Map<String, String> processedMap = preprocessPlaceholderMap(placeholderMap);
        log.info("开始批量替换占位符，共 {} 个", processedMap.size());
        // 优先尝试批量替换（性能更好）
        try {
            mainDocumentPart.variableReplace(processedMap);
            // 验证批量替换是否真正成功（检查是否还有占位符残留）
            int remainingPlaceholders = 0;
            for (String placeholder : processedMap.keySet()) {
                String checkFormat = "${" + placeholder + "}";
                if (containsPlaceholder(mainDocumentPart, checkFormat)) {
                    remainingPlaceholders++;
                }
            }
            if (remainingPlaceholders == 0) {
                log.info("批量占位符替换成功，所有 {} 个占位符都已替换", processedMap.size());
                return;
            } else {
                log.warn("批量替换后仍有 {} 个占位符未被替换，降级为逐个处理", remainingPlaceholders);
            }
        } catch (Exception e) {
            log.warn("批量替换发生异常，降级为逐个替换: {}", e.getMessage());
        }

        // 降级策略：逐个替换（容错性更好）
        int successCount = 0;
        int failCount = 0;
        for (Map.Entry<String, String> entry : processedMap.entrySet()) {
            String placeholder = entry.getKey();
            String replacement = entry.getValue();
            try {
                replaceSinglePlaceholder(mainDocumentPart, placeholder, replacement);
                successCount++;
            } catch (Exception e) {
                log.error("占位符 [{}] 替换失败: {}", placeholder, e.getMessage());
                failCount++;
            }
        }

        log.info("逐个替换完成，成功: {} 个，失败: {} 个", successCount, failCount);
    }


    /**
     * 预处理占位符映射，确保格式符合 docx4j 预期
     *
     * @param originalMap 原始占位符映射
     * @return 处理后的占位符映射
     */
    public static Map<String, String> preprocessPlaceholderMap(Map<String, String> originalMap) {
        if (originalMap == null || originalMap.isEmpty()) {
            return new HashMap<>(16);
        }
        
        Map<String, String> processedMap = new HashMap<>(16);
        
        for (Map.Entry<String, String> entry : originalMap.entrySet()) {
            String key = entry.getKey();
            String value = entry.getValue() != null ? entry.getValue() : "";
            
            // 确保占位符格式符合 docx4j 预期
            String formattedKey = formatPlaceholder(key);
            processedMap.put(formattedKey, value);
        }
        
        return processedMap;
    }

    /**
     * 格式化占位符，确保符合 docx4j 预期格式
     * 
     * docx4j 的 variableReplace 方法期望的 Map key 格式是纯变量名，不包含 ${} 或 {{}} 等括号
     * 例如：Word 文档中写 ${companyName}，但 Map 的 key 应该是 "companyName"
     *
     * @param placeholder 原始占位符
     * @return 格式化后的占位符（纯变量名）
     */
    public static String formatPlaceholder(String placeholder) {
        if (!StringUtils.hasText(placeholder)) {
            return placeholder;
        }
        
        // 如果占位符包含 ${} 格式，去掉外层括号只保留变量名
        if (placeholder.startsWith("${") && placeholder.endsWith("}")) {
            return placeholder.substring(2, placeholder.length() - 1);
        }
        
        // 如果占位符包含 {{}} 格式，去掉外层括号只保留变量名
        if (placeholder.startsWith("{{") && placeholder.endsWith("}}")) {
            return placeholder.substring(2, placeholder.length() - 2);
        }
        
        // 直接返回原始占位符名称（已经是纯变量名）
        return placeholder;
    }

    /**
     * 检查文档中是否还包含指定的占位符
     * 用于验证替换是否成功（docx4j 替换失败时不抛异常，需要手动检查）
     *
     * @param mainDocumentPart 主文档部分
     * @param format 要检查的占位符格式
     * @return true 如果文档中仍包含该占位符，false 表示已被替换
     */
    private static boolean containsPlaceholder(MainDocumentPart mainDocumentPart, String format) {
        try {
            String documentText = mainDocumentPart.getContent().toString();
            return documentText.contains(format);
        } catch (Exception e) {
            log.debug("检查占位符时发生异常: {}", e.getMessage());
            // 出现异常时假设不包含
            return false;
        }
    }

    /**
     * 在文档中进行多格式文本替换
     * 这是 docx4j variableReplace 失败时的备用方案
     * 特别处理 docx4j 的静默失败问题（替换失败不抛异常，占位符仍存在）
     *
     * @param mainDocumentPart 主文档部分
     * @param placeholder 占位符变量名
     * @param replacement 替换文本
     * @throws Exception 处理异常
     */
    public static void replaceTextInDocument(MainDocumentPart mainDocumentPart, String placeholder, String replacement) throws Exception {
        if (mainDocumentPart == null || !StringUtils.hasText(placeholder)) {
            throw new IllegalArgumentException("文档部分和占位符不能为空");
        }
        
        String safeReplacement = replacement != null ? replacement : "";
        
        try {
            // 尝试多种格式的文本替换，按常用程度排序
            String[] searchFormats = {
                    // ${placeholder} - docx4j 标准格式
                "${" + placeholder + "}",
                    // {{placeholder}} - 常见的模板格式
                "{{" + placeholder + "}}",
                    // placeholder - 纯变量名
                placeholder
            };
            
            boolean replacementSuccess = false;
            for (String format : searchFormats) {
                // 先检查文档中是否包含该格式的占位符
                if (!containsPlaceholder(mainDocumentPart, format)) {
                    log.debug("文档中不包含格式 [{}] 的占位符，跳过", format);
                    continue;
                }
                
                try {
                    // 使用 docx4j 6.1.0 进行替换
                    java.util.HashMap<String, String> mappings = new java.util.HashMap<>();
                    mappings.put(format, safeReplacement);
                    mainDocumentPart.variableReplace(mappings);
                    
                    // 验证替换是否真正成功（docx4j 静默失败的关键处理）
                    if (!containsPlaceholder(mainDocumentPart, format)) {
                        log.debug("成功替换格式 [{}] 的占位符", format);
                        replacementSuccess = true;
                        break;
                    } else {
                        log.debug("格式 [{}] 替换后仍存在，可能是 Word 文档中占位符被分割", format);
                    }
                } catch (Exception e) {
                    log.debug("格式 [{}] 替换时发生异常: {}", format, e.getMessage());
                }
            }
            
            if (!replacementSuccess) {
                log.warn("所有格式尝试后占位符 [{}] 仍未被替换，可能原因：", placeholder);
                log.warn("1. Word 文档中不存在该占位符");
                log.warn("2. 占位符在 Word 中被格式化分割（如 ${com}panyName）");
                log.warn("3. 占位符格式与预期不匹配");
            }
            
        } catch (Exception e) {
            log.warn("文本替换过程发生异常: {} -> {}", placeholder, safeReplacement, e);
            throw new Exception("文本替换失败: " + e.getMessage(), e);
        }
    }

    /**
     * 执行单个占位符的变量替换
     * 优先使用 docx4j 的 variableReplace，失败时降级为多格式文本替换
     * 包含 docx4j 静默失败的验证逻辑
     *
     * @param mainDocumentPart 主文档部分
     * @param placeholder 占位符变量名（已格式化，纯变量名）
     * @param replacement 替换值
     */
    public static void replaceSinglePlaceholder(MainDocumentPart mainDocumentPart, String placeholder, String replacement) {
        if (mainDocumentPart == null || !StringUtils.hasText(placeholder)) {
            log.warn("文档部分或占位符为空，跳过替换");
            return;
        }
        String safeReplacement = replacement != null ? replacement : "";
        // 检查标准格式
        String checkFormat = "${" + placeholder + "}";
        // 先检查文档中是否包含该占位符
        if (!containsPlaceholder(mainDocumentPart, checkFormat)) {
            log.debug("文档中不包含占位符 [{}]，跳过替换", placeholder);
            return;
        }
        try {
            // 优先使用 docx4j 的变量替换功能
            HashMap<String, String> singleReplacement = new HashMap<>(16);
            singleReplacement.put(placeholder, safeReplacement);
            mainDocumentPart.variableReplace(singleReplacement);
            // 验证替换是否真正成功（docx4j 静默失败检测）
            if (!containsPlaceholder(mainDocumentPart, checkFormat)) {
                log.debug("成功替换占位符: {} -> {}", placeholder, safeReplacement);
                return;
            } else {
                log.debug("占位符 [{}] 替换后仍存在，可能被格式化分割，尝试多格式替换", placeholder);
            }
        } catch (Exception e) {
            log.debug("占位符变量替换发生异常: {}", placeholder, e);
        }
        // 降级为多格式文本替换
        try {
            replaceTextInDocument(mainDocumentPart, placeholder, safeReplacement);
        } catch (Exception textReplaceException) {
            log.error("占位符 [{}] 的所有替换方式都失败了: {}", placeholder, textReplaceException.getMessage());
        }
    }


}