package cn.iocoder.yudao.module.pms.util;

import com.google.common.collect.ImmutableList;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.util.Units;
import org.apache.poi.xwpf.usermodel.*;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;
import org.springframework.core.io.ClassPathResource;

import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigInteger;
import java.util.List;

public class SafetyObservationCardGenerator {
    public static class CheckItem {
        private String parent;          // 中文父项（如：个人防护）
        private String child;           // 中文子项（如：头部）
        private String englishParent;   // 英文父项（如：Personal Protection Equipment）
        private String englishChild;    // 英文子项（如：Head）

        public CheckItem(String parent, String child, String englishParent, String englishChild) {
            this.parent = parent;
            this.child = child;
            this.englishParent = englishParent;
            this.englishChild = englishChild;
        }

        // getter
        public String getParent() {
            return parent;
        }

        public String getChild() {
            return child;
        }

        public String getEnglishParent() {
            return englishParent;
        }

        public String getEnglishChild() {
            return englishChild;
        }
    }
    // 新增入参：person(实施观察人员)、date(日期)、remark(观察描述)
    public static void generateCard(List<CheckItem> checkItems, String person, String date, String remark) {
        try (XWPFDocument document = new XWPFDocument();
             FileOutputStream out = new FileOutputStream("行为安全观察与沟通卡-中英双语.docx")) {

            // ========== 1. 生成中文表格 ==========
            generateChineseTable(document, checkItems, person, date, remark);

            // 换行分隔中英文表格
            document.createParagraph();

            // ========== 2. 生成英文表格 ==========
            generateEnglishTable(document, checkItems, person, date, remark);

            document.write(out);
            System.out.println("中英双语版安全观察卡生成成功！");

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 中文表格新增入参：person、date、remark
    private static void generateChineseTable(XWPFDocument document, List<CheckItem> checkItems, String person, String date, String remark) throws IOException, InvalidFormatException {
        // 1. 中文标题图片（保持原有逻辑）
        XWPFParagraph logoPara = document.createParagraph();
        logoPara.setAlignment(ParagraphAlignment.CENTER);
        XWPFRun logoRun = logoPara.createRun();

        String imagePath = "pic/keruishiyoujishu.png";
        InputStream imageStream = new ClassPathResource(imagePath).getInputStream();

        XWPFRun run = logoPara.createRun();
        run.addPicture(imageStream, XWPFDocument.PICTURE_TYPE_PNG, "keruishiyoujishu.png",
                Units.toEMU(250), Units.toEMU(30));

        document.createParagraph();

        // 2. 中文表格主体
        XWPFTable table = document.createTable(9, 3);
        table.setWidth("100%");
        while (table.getRows().size() > 0) {
            table.removeRow(0);
        }
        table.setWidth("100%");

        // 标题行
        XWPFTableRow titleRow = table.createRow();
        mergeCellsHorizontally(titleRow, 0, 2);
        XWPFTableCell titleCell = titleRow.getCell(0);
        setTitleStyle(titleCell, "行为安全观察与沟通卡", true, ParagraphAlignment.CENTER, "FFFFFF");

        // 黄色提示栏
        XWPFTableRow tipRow = table.createRow();
        mergeCellsHorizontally(tipRow, 0, 2);
        XWPFTableCell tipCell = tipRow.getCell(0);
        setTipTextStyle(tipCell, "若有任何不安全，请在小项前面□内打√。大项完全安全，请在大项后面□内打√。", true, ParagraphAlignment.LEFT, "FFFF00");

        // 行3：个人防护 | 规范操作 | 观察描述
        XWPFTableRow headerRow1 = table.createRow();
        setCellStyle(headerRow1.getCell(0), "个人防护□", true, ParagraphAlignment.LEFT, "DCE6F1");
        setCellStyle(headerRow1.getCell(1), "规范操作□", true, ParagraphAlignment.LEFT, "DCE6F1");
        // 渲染remark到观察描述后
        setCellStyle(headerRow1.getCell(2), "观察描述：" + (remark == null ? "" : remark), true, ParagraphAlignment.LEFT, "DCE6F1");

        // 行4：个人防护明细 | 规范操作明细 | 空
        XWPFTableRow row4 = table.createRow();
        String ppeText = getCheckedText(checkItems, "parent", "child",
                "个人防护",
                "个人防护用品是否齐全、规范？\n" +
                        "□ 头部\n" +
                        "□ 脸部及眼部\n" +
                        "□ 听力保护\n" +
                        "□ 呼吸系统\n" +
                        "□ 胳膊和手\n" +
                        "□ 躯干\n" +
                        "□ 腿部和脚\n" +
                        "□ 其他 _______________");
        String opText = getCheckedText(checkItems, "parent", "child",
                "规范操作",
                "员工是否严格执行操作规程？\n□ 不按规定的方法操作\n□ 不采取安全措施进行操作\n□ 其他 _______________");
        setCellStyle(row4.getCell(0), ppeText, false, ParagraphAlignment.LEFT, "FFFFFF");
        setCellStyle(row4.getCell(1), opText, false, ParagraphAlignment.LEFT, "FFFFFF");
        setCellStyle(row4.getCell(2), "", false, ParagraphAlignment.LEFT, "E6EBF5");

        // 行5：规范指挥 | 人员位置 | 空
        XWPFTableRow headerRow2 = table.createRow();
        setCellStyle(headerRow2.getCell(0), "规范指挥□", true, ParagraphAlignment.LEFT, "DCE6F1");
        setCellStyle(headerRow2.getCell(1), "人员位置□", true, ParagraphAlignment.LEFT, "DCE6F1");
        setCellStyle(headerRow2.getCell(2), "", false, ParagraphAlignment.LEFT, "DCE6F1");

        // 行6：规范指挥明细 | 人员位置明细 | 安全行为描述
        XWPFTableRow row10 = table.createRow();
        String cmdText1 = getCheckedText(checkItems, "parent", "child",
                "规范指挥",
                "是否违章指挥？\n□ 指挥信号不正确/不清楚\n□ 多人指挥，信号不统一\n□ 非特殊情况下越权指挥\n□ 明知危险仍强令冒险作业\n□ 特殊作业前没有进行作业申请/风险分析\n□ 其他 _______________");
        String posText1 = getCheckedText(checkItems, "parent", "child",
                "人员位置",
                "人员站位是否安全？\n□ 碰撞到物体\n□ 被物体夹住/手扶握物体部位不正确\n□ 跌倒/坠落/陷入物体之中\n□ 被物体砸到\n□ 接触极高/极低温度/电流/电击\n□ 吸入/吸收/吞食有害物质\n□ 姿势不良/用力过度\n□ 其他 _______________");
        String safeText1 = "·观察到的安全行为或安全状态\n·鼓励安全行为或安全状态所采取的行动";
        setCellStyle(row10.getCell(0), cmdText1, false, ParagraphAlignment.LEFT, "FFFFFF");
        setCellStyle(row10.getCell(1), posText1, false, ParagraphAlignment.LEFT, "FFFFFF");
        setCellStyle(row10.getCell(2), safeText1, true, ParagraphAlignment.LEFT, "E6EBF5");

        // 行7：规范指挥明细 | 人员位置明细 | 安全行为描述
        XWPFTableRow row6 = table.createRow();
        setRowHeight(row6, 1900);
        setCellStyle(row6.getCell(0), "", false, ParagraphAlignment.LEFT, "FFFFFF");
        setCellStyle(row6.getCell(1), "", false, ParagraphAlignment.LEFT, "FFFFFF");
        setCellStyle(row6.getCell(2), "", false, ParagraphAlignment.LEFT, "FFFFFF");

        // 行8：规范指挥明细 | 人员位置明细 | 不安全行为描述
        XWPFTableRow row7 = table.createRow();
        setRowHeight(row7, 500);
        String safeText2 = "·观察到的不安全行为或不安全状态\n·即刻的纠正行动\n·预防再发生的行动";
        setCellStyle(row7.getCell(0), "", false, ParagraphAlignment.LEFT, "FFFFFF");
        setCellStyle(row7.getCell(1), "", false, ParagraphAlignment.LEFT, "FFFFFF");
        setCellStyle(row7.getCell(2), safeText2, true, ParagraphAlignment.LEFT, "E6EBF5");

        // 行9：作业场所 | 空 | 空
        XWPFTableRow headerRow3 = table.createRow();
        mergeCellsHorizontally(headerRow3, 0, 1);
        setCellStyle(headerRow3.getCell(0), "作业场所□ \n作业场所、工作环境是否存在不安全状态或其他安全隐患？", true, ParagraphAlignment.LEFT, "DCE6F1");
        setCellStyle(headerRow3.getCell(2), "", false, ParagraphAlignment.LEFT, "E6EBF5");

        // 行10：作业场所明细 | 空 | 不安全行为描述
        XWPFTableRow row8 = table.createRow();
        String houseText = getCheckedText(checkItems, "parent", "child",
                "作业场所",
                "□ 作业场所杂乱\n□ 作业空间狭小\n□ 堵塞安全通道\n□ 地面滑（水/雨/雪/油污等）\n□ 物体/工具放置位置不当        \n□ 危险场所没有标志/标志不清\n□ 照明光线不良");
        String secondText = getCheckedText(checkItems, "parent", "child",
                "作业场所",
                "□ 带电装置带电部分裸露\n□ 设备无防护/防护装置不当\n□ 未工完料净场地清/垃圾未分类存放\n□ 通风不良/氧气含量未达标\n□ 其他 _______________");
        setCellStyle(row8.getCell(0), houseText, false, ParagraphAlignment.LEFT, "FFFFFF");
        setCellStyle(row8.getCell(1), secondText, false, ParagraphAlignment.LEFT, "FFFFFF");
        setCellStyle(row8.getCell(2), "", false, ParagraphAlignment.LEFT, "FFFFFF");

        // 底部信息行 - 渲染person和date
        XWPFTableRow footerRow = table.createRow();
        mergeCellsHorizontally(footerRow, 0, 2);
        // 替换实施观察人员和日期的占位符
        String footerText = String.format(
                "观察区域: ____________  实施观察人员: %s  被观察岗位：____________  \n被观察人员：□员工 □承包商 □供应商 日期: %s 时间：___点___分到___点___分",
                (person == null ? "____________" : person),
                (date == null ? "__________" : date)
        );
        setCellStyle(footerRow.getCell(0), footerText, true, ParagraphAlignment.LEFT, "FFFFFF");

        // 垂直合并单元格
        mergeCellsVertically(table, 2, 4, 2);
        mergeCellsVertically(table, 5,7,0);
        mergeCellsVertically(table, 5,7,1);
        mergeCellsVertically(table, 7, 8, 2);
    }

    // 英文表格新增入参：person、date、remark
    private static void generateEnglishTable(XWPFDocument document, List<CheckItem> checkItems, String person, String date, String remark) {
        // 移除独立的英文标题段落，直接在表格内创建标题行
        document.createParagraph(); // 仅保留空行分隔

        // 2. 英文表格主体
        XWPFTable table = document.createTable(9, 3);
        table.setWidth("100%");
        while (table.getRows().size() > 0) {
            table.removeRow(0);
        }
        table.setWidth("100%");

        // ========== 核心修改：新增英文表格标题行 ==========
        XWPFTableRow titleRow = table.createRow();
        mergeCellsHorizontally(titleRow, 0, 2);
        XWPFTableCell titleCell = titleRow.getCell(0);
        // 复用标题样式，适配英文
        setTitleStyle(titleCell, "Safety Training Observation Program Card", true, ParagraphAlignment.CENTER, "FFFFFF");

        // 黄色提示栏（对应图片中的 Please mark "√" if any unsafe behavior or conditions）
        XWPFTableRow tipRow = table.createRow();
        mergeCellsHorizontally(tipRow, 0, 2);
        XWPFTableCell tipCell = tipRow.getCell(0);
        setTipTextStyle(tipCell, "Please mark \"√\" if any unsafe behavior or conditions", true, ParagraphAlignment.LEFT, "FFFF00");

        // 行2：Personal Protection Equipment | Tools and Equipment | Observation Description - 渲染remark
        XWPFTableRow headerRow1 = table.createRow();
        setCellStyle(headerRow1.getCell(0), "Personal Protection Equipment □", true, ParagraphAlignment.LEFT, "DCE6F1");
        setCellStyle(headerRow1.getCell(1), "Tools and Equipment □", true, ParagraphAlignment.LEFT, "DCE6F1");
        setCellStyle(headerRow1.getCell(2), "Observation Description: " + (remark == null ? "" : remark), true, ParagraphAlignment.LEFT, "DCE6F1");

        // 行3：个人防护英文明细 | 工具设备明细 | 空
        XWPFTableRow row3 = table.createRow();
        String ppeEnglishText = getCheckedText(checkItems, "englishParent", "englishChild",
                "Personal Protection Equipment",
                "□ Head\n" +
                        "□ Eyes / Face\n" +
                        "□ Hearing Protection\n" +
                        "□ Respiratory Protection\n" +
                        "□ Arm / Hands\n" +
                        "□ Body\n" +
                        "□ Legs / Feet\n" +
                        "□ Other _______________");
        String toolEnglishText = getCheckedText(checkItems, "englishParent", "englishChild",
                "Tools and Equipment",
                "□ Using Wrong Tools & Equipment\n" +
                        "□ Incorrectly Use of Tools & Equipment\n" +
                        "□ Using defective Tools & Equipment\n" +
                        "□ Instruments not Verification\n" +
                        "□ Without Pre-job Inspection\n" +
                        "□ Other _______________");
        setCellStyle(row3.getCell(0), ppeEnglishText, false, ParagraphAlignment.LEFT, "FFFFFF");
        setCellStyle(row3.getCell(1), toolEnglishText, false, ParagraphAlignment.LEFT, "FFFFFF");
        setCellStyle(row3.getCell(2), "", false, ParagraphAlignment.LEFT, "E6EBF5");

        // 行4：Standardized Command | Position of People | Safe Act Observed
        XWPFTableRow headerRow2 = table.createRow();
        setCellStyle(headerRow2.getCell(0), "Standardized Command □", true, ParagraphAlignment.LEFT, "DCE6F1");
        setCellStyle(headerRow2.getCell(1), "Position of People □", true, ParagraphAlignment.LEFT, "DCE6F1");
        setCellStyle(headerRow2.getCell(2), "", true, ParagraphAlignment.LEFT, "E6EBF5");

        // 行5：规范指挥英文明细 | 人员位置英文明细 | 空
        XWPFTableRow row5 = table.createRow();
        String cmdEnglishText = getCheckedText(checkItems, "englishParent", "englishChild",
                "Standardized Command",
                "□ Incorrect / unclear signals\n" +
                        "□ Multiple , signals inconsistent\n" +
                        "□ Overstepping authority in non-special circumstances\n" +
                        "□ Enforcing dangerous operations despite knowing the risks\n" +
                        "□ Failure to conduct work application / risk analysis before special operations\n" +
                        "□ Other _______________");
        String posEnglishText = getCheckedText(checkItems, "englishParent", "englishChild",
                "Position of People",
                "□ Striking Against Object\n" +
                        "□ Struck by Objects / Pinch Point\n" +
                        "□ Slip / Trip / Falling\n" +
                        "□ Exposure to Extreme Temperature(Hot/Cold)\n" +
                        "□ Electric Shock\n" +
                        "□ Exposure to Chemicals\n" +
                        "□ Caught in ,on or between Objects\n" +
                        "□ Awkward Posture\n" +
                        "□ Other _______________");
        setCellStyle(row5.getCell(0), cmdEnglishText, false, ParagraphAlignment.LEFT, "FFFFFF");
        setCellStyle(row5.getCell(1), posEnglishText, false, ParagraphAlignment.LEFT, "FFFFFF");
        setCellStyle(row5.getCell(2), "Safe Act Observed Actions Take to Encourage Continued Safe Performance", false, ParagraphAlignment.LEFT, "E6EBF5");

        // 行6：空 | 空 | Corrective Actions for Unsafe Behaviors Observed
        XWPFTableRow row6 = table.createRow();
        setRowHeight(row6, 1900);
        setCellStyle(row6.getCell(0), "", false, ParagraphAlignment.LEFT, "FFFFFF");
        setCellStyle(row6.getCell(1), "", false, ParagraphAlignment.LEFT, "FFFFFF");
        setCellStyle(row6.getCell(2), "", false, ParagraphAlignment.LEFT, "FFFFFF");

        // 行7：空 | 空 | 纠正措施明细
        XWPFTableRow row7 = table.createRow();
        setRowHeight(row7, 500);
        String correctiveText = "Corrective Actions for Unsafe Behaviors Observed";
        setCellStyle(row7.getCell(0), "", false, ParagraphAlignment.LEFT, "FFFFFF");
        setCellStyle(row7.getCell(1), "", false, ParagraphAlignment.LEFT, "FFFFFF");
        setCellStyle(row7.getCell(2), correctiveText, true, ParagraphAlignment.LEFT, "E6EBF5");

        // 行8：Housekeeping | 空 | 空
        XWPFTableRow headerRow3 = table.createRow();
        mergeCellsHorizontally(headerRow3, 0, 1);
        setCellStyle(headerRow3.getCell(0), "Housekeeping □", true, ParagraphAlignment.LEFT, "DCE6F1");
        setCellStyle(headerRow3.getCell(2), "", false, ParagraphAlignment.LEFT, "E6EBF5");

        // 行9：作业场所英文明细 | 空 | 空
        XWPFTableRow row8 = table.createRow();
        String houseEnglishText1 = getCheckedText(checkItems, "englishParent", "englishChild",
                "Housekeeping",
                "□ Poor Housekeeping\n" +
                        "□ Narrow work area\n" +
                        "□ Blocked Evacuation Routes\n" +
                        "□ Slippery floor (Water / Rain / Snow / Oil etc.)\n" +
                        "□ Improperly Placed Objects / Tools\n" +
                        "□ No or unclear safety signs in hazardous areas\n" +
                        "□ Poor lighting\n" +
                        "□ Other _______________");
        String houseEnglishText2 = getCheckedText(checkItems, "englishParent", "englishChild",
                "Housekeeping",
                "□ Exposed live parts of energized equipment\n" +
                        "□ Without Protection/inadequate protection device\n" +
                        "□ Work not completed, and materials and garbage not cleaned and stored\n" +
                        "□ Poor Ventilation\n" +
                        "□ Oxygen content not up to standard\n" +
                        "□ Other _______________");
        setCellStyle(row8.getCell(0), houseEnglishText1, false, ParagraphAlignment.LEFT, "FFFFFF");
        setCellStyle(row8.getCell(1), houseEnglishText2, false, ParagraphAlignment.LEFT, "FFFFFF");
        setCellStyle(row8.getCell(2), "", false, ParagraphAlignment.LEFT, "E6EBF5");

        // 底部信息行（英文）- 渲染person和date
        XWPFTableRow footerRow = table.createRow();
        mergeCellsHorizontally(footerRow, 0, 2);
        String footerEnglishText = String.format(
                "Observation Location: ____________  Observer: %s  \nDate: %s  Time: __________\nReporting helps to protect Health, Safety and Environment, reporting is aimed at identifying corrective actions.",
                (person == null ? "____________" : person),
                (date == null ? "__________" : date)
        );
        setCellStyle(footerRow.getCell(0), footerEnglishText, true, ParagraphAlignment.LEFT, "FFFFFF");

        // 垂直合并单元格（与中文表格对齐）
        mergeCellsVertically(table, 2, 4, 2);
        mergeCellsVertically(table, 5,7,0);
        mergeCellsVertically(table, 5,7,1);
        mergeCellsVertically(table, 7, 8, 2);
    }

    // 通用勾选方法：支持中文/英文字段匹配（通过fieldParent/fieldChild指定字段名）
    private static String getCheckedText(List<CheckItem> checkItems, String fieldParent, String fieldChild, String targetParent, String originalText) {
        if (checkItems == null || checkItems.isEmpty()) {
            return originalText;
        }
        String text = originalText;
        for (CheckItem item : checkItems) {
            String parent = "";
            String child = "";
            // 根据字段名匹配中文/英文父/子项
            switch (fieldParent) {
                case "parent":
                    parent = item.getParent();
                    break;
                case "englishParent":
                    parent = item.getEnglishParent();
                    break;
            }
            switch (fieldChild) {
                case "child":
                    child = item.getChild();
                    break;
                case "englishChild":
                    child = item.getEnglishChild();
                    break;
            }
            // 匹配父项+子项，替换勾选框
            if (targetParent.equals(parent)) {
                String target = "□ " + child;
                text = text.replace(target, "☑ " + child);
            }
        }
        return text;
    }

    public static byte[] generateCardToBytes(List<CheckItem> checkItems, String person, String date, String remark) throws Exception {
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        try (XWPFDocument document = new XWPFDocument()) {
            // 复用原有生成逻辑
            generateChineseTable(document, checkItems, person, date, remark);
            document.createParagraph();
            generateEnglishTable(document, checkItems, person, date, remark);
            // 写入字节流
            document.write(bos);
            return bos.toByteArray();
        } finally {
            bos.close();
        }
    }


    // 测试方法 - 新增person、date、remark参数示例
    public static void main(String[] args) {
        // 示例：勾选 个人防护-头部（对应英文Head）、规范操作-其他（对应英文Other）、作业场所-地面滑（对应英文Slippery floor）
        List<CheckItem> checkItems = ImmutableList.of(
                new CheckItem("个人防护", "头部", "Personal Protection Equipment", "Head"),
                new CheckItem("规范操作", "其他", "Tools and Equipment", "Other"),
                new CheckItem("作业场所", "地面滑（水/雨/雪/油污等）", "Housekeeping", "Slippery floor (Water / Rain / Snow / Oil etc.)")
        );
        // 测试参数
        String person = "张三";
        String date = "2024-05-20";
        String remark = "\n现场作业人员防护措施到位，操作规范，无安全隐患";
        generateCard(checkItems, person, date, remark);
    }

    // ========== 以下工具方法保持不变（仅适配英文字体） ==========
    private static void setRowHeight(XWPFTableRow row, int heightInTwips) {
        CTRow ctTr = row.getCtRow();
        CTTrPr trPr = ctTr.getTrPr() == null ? ctTr.addNewTrPr() : ctTr.getTrPr();
        CTHeight trHeight = trPr.addNewTrHeight();
        trHeight.setVal(BigInteger.valueOf(heightInTwips));
        trHeight.setHRule(STHeightRule.EXACT);
    }

    private static void setTitleStyle(XWPFTableCell cell, String text, boolean bold, ParagraphAlignment align, String bgColor) {
        clearCellContent(cell);

        XWPFParagraph para = cell.addParagraph();
        para.setAlignment(align);
        XWPFRun run = para.createRun();
        run.setText(text);
        run.setFontSize(14);
        // 区分中英文设置字体
        run.setFontFamily(isEnglish(text) ? "Arial" : "宋体");
        run.setBold(bold);
        run.setColor("4472C4");
        cell.setColor(bgColor);
        setCellBorder(cell);
    }

    private static void setTipTextStyle(XWPFTableCell cell, String text, boolean bold, ParagraphAlignment align, String bgColor) {
        clearCellContent(cell);

        CTTcPr tcPr = cell.getCTTc().getTcPr() != null ? cell.getCTTc().getTcPr() : cell.getCTTc().addNewTcPr();
        CTVerticalJc vAlign = tcPr.addNewVAlign();
        vAlign.setVal(STVerticalJc.TOP);

        XWPFParagraph paragraph = cell.addParagraph();
        paragraph.setAlignment(align);
        paragraph.setSpacingAfter(100);
        paragraph.setSpacingBefore(100);
        paragraph.setIndentationFirstLine(288);

        XWPFRun run = paragraph.createRun();
        run.setText(text.trim());
        run.setFontSize(9);
        run.setFontFamily(isEnglish(text) ? "Arial" : "宋体");
        run.setBold(true);
        run.setColor("003366");
        run.setTextPosition(10);

        cell.setColor(bgColor);
        setCellBorder(cell);
    }

    private static void setCellStyle(XWPFTableCell cell, String text, boolean bold, ParagraphAlignment align, String bgColor) {
        clearCellContent(cell);

        CTTcPr tcPr = cell.getCTTc().getTcPr() != null ? cell.getCTTc().getTcPr() : cell.getCTTc().addNewTcPr();
        CTVerticalJc vAlign = tcPr.addNewVAlign();
        vAlign.setVal(STVerticalJc.TOP);

        String[] lines = text.split("\n");
        for (int i = 0; i < lines.length; i++) {
            String line = lines[i];
            XWPFParagraph paragraph = cell.addParagraph();
            paragraph.setAlignment(align);
            paragraph.setSpacingAfter(50);
            paragraph.setSpacingBefore(0);

            if (line.startsWith("□")||line.startsWith("☑")) {
                paragraph.setIndentationFirstLine(288);
            } else {
                paragraph.setIndentationFirstLine(144);
            }

            XWPFRun run = paragraph.createRun();
            run.setText(line.trim());
            run.setFontSize(9);
            if (isEnglish(line)) {
                run.setFontFamily("Arial");
            } else {
                run.setFontFamily("宋体");
            }
            run.setBold(bold);
            run.setTextPosition(12);
        }

        if (lines.length == 0 && text.isEmpty()) {
            XWPFParagraph paragraph = cell.addParagraph();
            paragraph.setAlignment(align);
            XWPFRun run = paragraph.createRun();
            run.setText("");
        }

        cell.setColor(bgColor);
        setCellBorder(cell);
    }

    // 辅助方法：判断文本是否为英文
    private static boolean isEnglish(String text) {
        return text.matches("^[a-zA-Z\\s\\.,:;\"'\\(\\)/\\-]+$");
    }

    private static void clearCellContent(XWPFTableCell cell) {
        List<XWPFParagraph> paragraphs = cell.getParagraphs();
        while (paragraphs != null && !paragraphs.isEmpty()) {
            cell.removeParagraph(0);
            paragraphs = cell.getParagraphs();
        }
        List<XWPFTable> tables = cell.getTables();
        while (tables != null && !tables.isEmpty()) {
            cell.removeTable(0);
            tables = cell.getTables();
        }
    }

    private static void setCellBorder(XWPFTableCell cell) {
        CTTcPr tcPr = cell.getCTTc().getTcPr() != null ? cell.getCTTc().getTcPr() : cell.getCTTc().addNewTcPr();
        CTTcBorders borders = tcPr.getTcBorders() != null ? tcPr.getTcBorders() : tcPr.addNewTcBorders();

        STBorder.Enum borderStyle = STBorder.SINGLE;
        borders.addNewTop().setVal(borderStyle);
        borders.getTop().setColor("000000");
        borders.addNewBottom().setVal(borderStyle);
        borders.getBottom().setColor("000000");
        borders.addNewLeft().setVal(borderStyle);
        borders.getLeft().setColor("000000");
        borders.addNewRight().setVal(borderStyle);
        borders.getRight().setColor("000000");
    }

    private static void mergeCellsHorizontally(XWPFTableRow row, int fromCol, int toCol) {
        while (row.getTableCells().size() <= toCol) {
            row.createCell();
        }

        CTTcPr firstPr = row.getCell(fromCol).getCTTc().getTcPr() != null ? row.getCell(fromCol).getCTTc().getTcPr() : row.getCell(fromCol).getCTTc().addNewTcPr();
        firstPr.addNewHMerge().setVal(STMerge.RESTART);

        for (int i = fromCol + 1; i <= toCol; i++) {
            CTTcPr pr = row.getCell(i).getCTTc().getTcPr() != null ? row.getCell(i).getCTTc().getTcPr() : row.getCell(i).getCTTc().addNewTcPr();
            pr.addNewHMerge().setVal(STMerge.CONTINUE);
        }
    }

    private static void mergeCellsVertically(XWPFTable table, int fromRow, int toRow, int col) {
        for (int rowIndex = fromRow; rowIndex <= toRow; rowIndex++) {
            XWPFTableCell cell = table.getRow(rowIndex).getCell(col);
            CTTcPr tcPr = cell.getCTTc().getTcPr() != null ? cell.getCTTc().getTcPr() : cell.getCTTc().addNewTcPr();
            STMerge.Enum mergeVal = (rowIndex == fromRow) ? STMerge.RESTART : STMerge.CONTINUE;
            tcPr.addNewVMerge().setVal(mergeVal);
            setCellBorder(cell);
        }
    }
}