package com.kingdee.shr.cmpdesign.web.handler.v2;

import com.kingdee.bos.BOSException;
import com.kingdee.bos.Context;
import com.kingdee.bos.metadata.entity.*;
import com.kingdee.bos.metadata.query.util.CompareType;
import com.kingdee.eas.base.permission.UserInfo;
import com.kingdee.eas.basedata.org.AdminOrgUnitInfo;
import com.kingdee.eas.basedata.org.PositionInfo;
import com.kingdee.eas.basedata.person.PersonInfo;
import com.kingdee.eas.hr.ats.AtsUtil;
import com.kingdee.eas.hr.ats.util.AtsDateUtils;
import com.kingdee.eas.hr.emp.*;
import com.kingdee.eas.util.app.ContextUtil;
import com.kingdee.eas.util.app.DbUtil;
import com.kingdee.jdbc.rowset.IRowSet;
import com.kingdee.shr.base.syssetting.context.SHRContext;
import com.kingdee.shr.base.syssetting.exception.SHRWebException;
import com.kingdee.shr.base.syssetting.web.dynamic.util.DynamicUtil;
import com.kingdee.shr.base.syssetting.web.dynamic.util.MD5;
import com.kingdee.shr.base.syssetting.web.json.JSONUtils;
import com.kingdee.shr.base.syssetting.web.util.UserUtil;
import com.kingdee.shr.cmpdesign.app.v2.bill.*;
import com.kingdee.shr.cmpdesign.web.handler.utils.AdvancedZipUtils;
import com.kingdee.util.DateTimeUtils;
import org.apache.log4j.Logger;
import org.apache.poi.xwpf.usermodel.*;
import org.springframework.ui.ModelMap;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.*;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.sql.SQLException;
import java.text.MessageFormat;
import java.util.*;
;

/**
 * @Title: AdjustSalaryApplyListHandlerEx
 * @Author 青梧
 * @Package com.kingdee.shr.cmpdesign.web.handler.v2
 * @Date 2026/1/14 15:37
 * @description: 套打
 */
public class AdjustSalaryApplyListHandlerEx extends AdjustSalaryApplyListHandler {
    private Context ctx = SHRContext.getInstance().getContext();
    private static Logger logger = Logger.getLogger(AdjustSalaryApplyListHandlerEx.class);
    // 定义薪资项编码常量
    private static final String BASIC_SALARY = "SCY002";       // 基本工资标准
    private static final String OVERTIME_SALARY = "SCY005";    // 加班工资标准
    private static final String SKILL_SALARY = "SCY003";       // 技能工资标准
    private static final String POST_ALLOWANCE = "SCY004";     // 岗位补助工资标准
    private static final String EDU_ALLOWANCE = "SCY006";      // 学历补助标准
    private static final String EXPENSE_ALLOWANCE = "SCY073";  // 费用补助标准
    private static final String TOTAL_SALARY = "SCY001";       // 标准薪资合计
    // 所有需要查询的薪资项编码
    private static final String[] SALARY_ITEM_CODES = {BASIC_SALARY, OVERTIME_SALARY, SKILL_SALARY, POST_ALLOWANCE, EDU_ALLOWANCE, EXPENSE_ALLOWANCE, TOTAL_SALARY};

    /**
     * 定调薪申请单套打
     *
     * @param request
     * @param response
     * @param modelMap
     * @throws SHRWebException
     */
    public void customPrintAction(HttpServletRequest request, HttpServletResponse response, ModelMap modelMap) throws SHRWebException, BOSException {
        try {
            String billId = this.getBillId(request);
            //获取临时地址
            HttpSession session = request.getSession();
            String tempFilePath = UserUtil.getUserTempDirAbsolutePath(session); //存放
            File tempFile = new File(tempFilePath);
            if (!tempFile.exists()) {
                tempFile.mkdirs();
            }
            Map map = new HashMap();
            Map<String, byte[]> files = new HashMap();
            //人员ID集合
            Map<String, Object> PersonMap = getAdjustSalaryApplyPersonIds(billId);
            Set personSet = (Set) PersonMap.get("personSet");
            //查询定调薪申请单
            SelectorItemCollection sic = new SelectorItemCollection();
            sic.add("*");
            sic.add("person.*");
            sic.add("primaryPosition.*");
            sic.add("personDep.*");
            FilterInfo filterInfo = new FilterInfo();
            FilterItemCollection filterItems = filterInfo.getFilterItems();
            filterItems.add(new FilterItemInfo("person.id", personSet, CompareType.INCLUDE));
            EntityViewInfo entityViewInfo = EntityViewInfo.getInstance(filterInfo, sic, null);
            //查询人员信息
            IPersonPosition iPersonPosition = PersonPositionFactory.getLocalInstance(ctx);
            PersonPositionCollection personPositionCollection = iPersonPosition.getPersonPositionCollection(entityViewInfo);
            for (int i = 0; i < personPositionCollection.size(); i++) {
                String fileName = "定调薪套打.docx";
                String txtNameHash = MD5.md5Hash(fileName);
                String realFileName = getEncryRealFileName(ctx, txtNameHash);
                String txtPath = tempFilePath + File.separator + realFileName;
                //  String fileStr = txtNameHash;
                // 1. 配置文件路径
                String templatePath = System.getProperty("EAS_HOME") + "/server/properties/templatePrint/dtxtdmb.docx";
                String pdfOutputPath = txtPath + ".docx";
                PersonPositionInfo personPositionInfo = personPositionCollection.get(i);
                //人员
                PersonInfo person = personPositionInfo.getPerson();
                //职位
                PositionInfo primaryPosition = personPositionInfo.getPrimaryPosition();
                //部门
                AdminOrgUnitInfo personDep = personPositionInfo.getPersonDep();
                // 2. 定义占位符-实际数据映射（同之前方案，可动态获取）
                Map<String, String> dataMap = new HashMap<>();
                String personId = person.getId().toString();
                //获取人员基本信息
                Map<String, String> personBaseMap = getPersonBaseInfo(personId);
                // 基础信息
                //人员分类
                dataMap.put("N", personBaseMap.getOrDefault("clName", "0"));         // 员工类型（表格标题）
                //定调薪单据-单据来源
                Map<String, String> data = (Map<String, String>) PersonMap.get(personId);
                dataMap.put("T", data.get("billSource"));       // 异动类型
                //定调薪单据编码
                dataMap.put("X", "SCY-R-HR-262-A/0");          // 编码
                // 员工个人信息
                dataMap.put("q", person.getName());            // 员工姓名
                dataMap.put("w", person.getNumber());      // 工号
                dataMap.put("e", AtsDateUtils.dateShortFormatToStr(person.getHireDate())); // 入职日期
                //教育经历
                dataMap.put("r", personBaseMap.getOrDefault("diplomaName", "0"));            // 学历
                dataMap.put("t", personBaseMap.getOrDefault("caName", "0"));          // 管理类别

                dataMap.put("y", personDep.getName());        // 所属组织
                dataMap.put("u", primaryPosition.getName());          // 职位
                dataMap.put("i", personBaseMap.getOrDefault("rankName", "0"));              // 职级
                dataMap.put("I", personBaseMap.get("schemeName")+"制"); // 工资类型
                Map<String, BigDecimal> adjustSalaryInfo = getAdjustSalaryInfo(personId);
                // 工资结构
                dataMap.put("A", adjustSalaryInfo.get(BASIC_SALARY).toString());  // 基本工资
                dataMap.put("B", adjustSalaryInfo.get(OVERTIME_SALARY).toString());// 加班工资
                dataMap.put("C", adjustSalaryInfo.get(SKILL_SALARY).toString());  // 技能工资
                dataMap.put("J", adjustSalaryInfo.get(POST_ALLOWANCE).toString());  // 岗位补贴
                dataMap.put("E", adjustSalaryInfo.get(EDU_ALLOWANCE).toString());  // 学历补贴
                dataMap.put("G", adjustSalaryInfo.get(TOTAL_SALARY).toString()); // 月薪合计
                dataMap.put("F", adjustSalaryInfo.get(EXPENSE_ALLOWANCE).toString());// 费用补贴
                // 生效日期
                dataMap.put("YYYYHHDD", data.get("stateDate"));
                // 执行流程：替换占位符 → 转 PDF
                batchReplaceWordPlaceholders(templatePath, pdfOutputPath, dataMap);
//            convertWordToPdf(pdfOutputPath, pdfOutputPath);

                File file = new File(pdfOutputPath);
                byte[] fileBytes = Files.readAllBytes(Paths.get(file.getAbsolutePath()));
                files.put(person.getName() + "_定调薪套打.docx", fileBytes);
            }
            UserInfo currentUserInfo = ContextUtil.getCurrentUserInfo(ctx);
            String downloadZipName = System.currentTimeMillis() + "print.zip";
            String zipName = downloadZipName + "_" + MD5.md5Hash(currentUserInfo.getId().toString());
            File userPathFile = new File(tempFilePath);
            if (!userPathFile.exists()) {
                userPathFile.mkdirs();
            }
            String zipPath = tempFilePath + File.separator + zipName;
            AdvancedZipUtils.createZipFromMultipleFiles(files, zipPath);
            Map<String, String> param = new HashMap<String, String>();
            param.put("method", "tmp");
            param.put("file", downloadZipName);
            param.put("filename", "AdjustSalaryApplyPrint.zip");
            String link = DynamicUtil.assembleUrl("/shr/downloadfile.do", param).replaceAll("\\+", "%20");
            map.put("msgType", "1");
            map.put("link", link);
            map.put("msg", "下载成功");
            // 可选：删除临时 Word 文件（如需保留可注释）
//            File tempWordFile = new File(pdfOutputPath);
//            if (tempWordFile.exists()) {
//                tempWordFile.delete();
//                System.out.println("临时 Word 文件已删除");
//            }
            JSONUtils.SUCCESS(map);
        } catch (Exception e) {
            e.printStackTrace();
            System.err.println("执行失败：" + e.getMessage());
        }
    }


    public Map<String, BigDecimal> getAdjustSalaryInfo(String personId) {
        // 1. 初始化Map，预设所有薪资项的默认值为"0"
        Map<String, BigDecimal> salaryMap = new HashMap<>();
        for (String code : SALARY_ITEM_CODES) {
            salaryMap.put(code, BigDecimal.ZERO);
        }
        // 2. 构建参数化SQL（避免SQL注入）
        StringBuilder sb = new StringBuilder();
        sb.append("select salary.FMoney as money ,item.fname_l2 as name ,item.fnumber as number\n");
        sb.append("from T_HR_SFixAdjustSalary salary\n");
        sb.append("left join T_HR_SCmpItem item on item.fid = salary.FCmpItemID\n");
        sb.append("where FPersonID = ? and FLeffectDay = ?");
        String sql = sb.toString();
        logger.error("getAdjustSalaryInfo--sql---" + sql);
        Object[] param = new Object[]{personId, "2199-12-31 00:00:00"};
        logger.error("getAdjustSalaryInfo--param---" + param);
        // 3. 执行查询（使用参数化方式，自动关闭资源）
        IRowSet iRowSet = null;
        try {
            // 假设DbUtil支持参数化查询，传入参数数组（替换原有的字符串拼接）
            iRowSet = DbUtil.executeQuery(ctx, sql, param);
            while (iRowSet.next()) {
                String number = iRowSet.getString("number");
                BigDecimal money = iRowSet.getBigDecimal("money").setScale(2, RoundingMode.HALF_UP);
                // 4. 只更新存在的薪资项，不存在的保持默认值0
                if (salaryMap.containsKey(number)) {
                    // 处理money为空的情况，确保不会存入null
                    salaryMap.put(number, money == null ? BigDecimal.ZERO : money);
                }
            }
        } catch (SQLException | BOSException e) {
            logger.error("查询薪资信息失败", e);
            // 异常时返回默认值（所有项都是0）
            return salaryMap;
        } finally {
            // 确保资源关闭（根据实际的IRowSet实现，添加关闭逻辑）
            if (iRowSet != null) {
                try {
                    iRowSet.close();
                } catch (SQLException e) {
                    logger.error("关闭IRowSet失败", e);
                }
            }
        }
        return salaryMap;
    }

    /**
     * 获取人员基本信息
     *
     * @param personId
     */
    public Map getPersonBaseInfo(String personId) throws BOSException, SQLException {
        Map baseMap = new HashMap();
        StringBuilder sb = new StringBuilder();
        sb.append("").append("\n");
        sb.append("select").append("\n");
        sb.append("    salaryScheme.fname_l2 as schemeName,").append("\n");
        sb.append("    rank.fname_l2 as rankName,").append("\n");
        sb.append("    degree.diplomaName as diplomaName ,").append("\n");
        sb.append("    ca.fname_l2 as caName,").append("\n");
        sb.append("cl.fname_l2 as clName").append("\n");
        sb.append("from").append("\n");
        sb.append("    T_BD_person person").append("\n");
        sb.append("    left join CT_MP_SalaryScheme salaryScheme on salaryScheme.fid = person.CFSalarySchemeID").append("\n");
        sb.append("    left join (").append("\n");
        sb.append("        select").append("\n");
        sb.append("            FPERSONID,").append("\n");
        sb.append("            jonGrade.fname_l2").append("\n");
        sb.append("        from").append("\n");
        sb.append("            T_HR_EmpPostRank rank").append("\n");
        sb.append("            left join T_HR_JobGrade jonGrade on rank.FJOBGRADEID = jonGrade.fid").append("\n");
        sb.append("        where").append("\n");
        sb.append("            FPERSONID = '" + personId + "'").append("\n");
        sb.append("            and FIsLatest = 1").append("\n");
        sb.append("    ) rank on rank.FPERSONID = person.fid").append("\n");
        sb.append("    left join (").append("\n");
        sb.append("        select").append("\n");
        sb.append("            degree.FPERSONID personId,").append("\n");
        sb.append("            diploma.FNAME_l2 as diplomaName").append("\n");
        sb.append("        from").append("\n");
        sb.append("            T_HR_PersonDegree degree").append("\n");
        sb.append("            left join T_BD_HRDiploma diploma on degree.FDiploma = diploma.fid").append("\n");
        sb.append("        where").append("\n");
        sb.append("            degree.fpersonid = '" + personId + "'").append("\n");
        sb.append("            and FIsSingle = 1").append("\n");
        sb.append("    ) degree on degree.personId = person.fid").append("\n");
        sb.append("    left join CT_MP_ManageCa ca on ca.fid = person.CFManageCaID").append("\n");
        sb.append("left join CT_MP_PersonnelCl cl on cl.fid = person.CFPersonnelClID").append("\n");
        sb.append("where").append("\n");
        sb.append("    person.fid = '" + personId + "'").append("\n");
        logger.error("getPersonBaseInfo--sql---" + sb.toString());
        IRowSet iRowSet = DbUtil.executeQuery(ctx, sb.toString());
        while (iRowSet.next()) {
            //工作类型
            baseMap.put("schemeName", iRowSet.getString("schemeName"));
            //职级
            baseMap.put("rankName", iRowSet.getString("rankName"));
            //学历
            baseMap.put("diplomaName", iRowSet.getString("diplomaName"));
            //人员分类
            baseMap.put("clName", iRowSet.getString("clName"));
            //管理类别
            baseMap.put("caName", iRowSet.getString("caName"));
        }
        return baseMap;
    }


    /******
     * 获取定调薪申请人员ID
     * @param billId
     * @return
     */
    public Map<String, Object> getAdjustSalaryApplyPersonIds(String billId) throws BOSException, SQLException {
        Map<String, Object> map = new HashMap<String, Object>();
        //套打人员ID
        Set set = new HashSet();
        //查询定调薪申请单
        FilterInfo filterInfo = new FilterInfo();
        FilterItemCollection filterItems = filterInfo.getFilterItems();
        filterItems.add(new FilterItemInfo("id", AtsUtil.toSet(billId), CompareType.INCLUDE));
        EntityViewInfo entityViewInfo = EntityViewInfo.getInstance(filterInfo, null, null);
        IAdjustSalaryApply iAdjustSalaryApply = AdjustSalaryApplyFactory.getLocalInstance(ctx);
        AdjustSalaryApplyCollection adjustSalaryApplyCollection = iAdjustSalaryApply.getAdjustSalaryApplyCollection(entityViewInfo);
        for (int i = 0; i < adjustSalaryApplyCollection.size(); i++) {
            AdjustSalaryApplyInfo adjustSalaryApplyInfo = adjustSalaryApplyCollection.get(i);
            String sql = "SELECT FPersonID as personId,FEffectDate as stateDate FROM T_HR_SAdjApplyEntry02cmp where  FBillID = '" + adjustSalaryApplyInfo.getId() + "'";
            IRowSet iRowSet = DbUtil.executeQuery(ctx, sql);
            while (iRowSet.next()) {
                String personId = iRowSet.getString("personId");
                Date stateDate = iRowSet.getDate("stateDate");
                set.add(personId);
                Map dataMap = new HashMap();
                dataMap.put("billSource", adjustSalaryApplyInfo.getBillSource().getAlias());
                dataMap.put("stateDate", DateTimeUtils.format(stateDate, "yyyy年hh月dd日"));
                map.put(personId, dataMap);
                map.put("personSet", set);
            }
        }
        return map;
    }


    // -------------- 第一步：批量替换 Word 占位符 --------------
    public static void batchReplaceWordPlaceholders(String templatePath, String tempWordPath, Map<String, String> dataMap) throws IOException {
        FileInputStream fis = new FileInputStream(templatePath);
        XWPFDocument document = new XWPFDocument(fis);

        // 替换段落和表格中的占位符
        replaceAllParagraphs(document, dataMap);
        replaceAllTables(document, dataMap);

        // 保存临时 Word 文档（替换后的 Word）
        FileOutputStream fos = new FileOutputStream(tempWordPath);
        document.write(fos);

        // 关闭资源
        fos.close();
        document.close();
        fis.close();
        System.out.println("Word 占位符替换完成，临时文件：" + tempWordPath);
    }

    // 替换文档中所有段落的占位符
    private static void replaceAllParagraphs(XWPFDocument document, Map<String, String> dataMap) {
        for (XWPFParagraph para : document.getParagraphs()) {
            replacePlaceholdersInParagraph(para, dataMap);
        }
    }

    // 替换文档中所有表格的占位符
    private static void replaceAllTables(XWPFDocument document, Map<String, String> dataMap) {
        for (XWPFTable table : document.getTables()) {
            for (XWPFTableRow row : table.getRows()) {
                for (XWPFTableCell cell : row.getTableCells()) {
                    for (XWPFParagraph para : cell.getParagraphs()) {
                        replacePlaceholdersInParagraph(para, dataMap);
                    }
                }
            }
        }
    }

    // 替换单个段落中的所有占位符
    private static void replacePlaceholdersInParagraph(XWPFParagraph para, Map<String, String> dataMap) {
        List<XWPFRun> runs = para.getRuns();
        if (runs == null || runs.isEmpty()) return;

        // 拼接段落文本
        StringBuilder paraText = new StringBuilder();
        for (XWPFRun run : runs) {
            String text = run.getText(0);
            if (text != null) paraText.append(text);
        }

        String original = paraText.toString();
        String replaced = original;

        // 批量替换所有占位符
        for (Map.Entry<String, String> entry : dataMap.entrySet()) {
            replaced = replaced.replace(entry.getKey(), entry.getValue());
        }

        // 更新段落内容（保留格式）
        if (!replaced.equals(original)) {
            for (XWPFRun run : runs) run.setText("", 0);
            runs.get(0).setText(replaced, 0);
        }
    }

    // -------------- 第二步：Word 转 PDF --------------
//    public static void convertWordToPdf(String wordPath, String pdfPath) throws Exception {
//        FileInputStream fis = new FileInputStream(pdfPath);
//        // 加载 Word 文档
//        com.aspose.words.Document doc = new com.aspose.words.Document();
//        // 配置 PDF 保存选项（可选，优化格式）
//        PdfSaveOptions saveOptions = new PdfSaveOptions();
//        saveOptions.setCompliance(PdfCompliance.PDF_A_1_B); // 兼容 PDF 标准
//        saveOptions.setExportGeneratorName(true); // 保留页眉页脚
//        // 保存为 PDF
//        doc.save(pdfPath, saveOptions);
//        System.out.println("PDF 转换完成，输出文件：" + pdfPath);
//    }

    /**
     * 9.9版本 下载url
     *
     * @param ctx
     * @param realFileName
     * @return
     */
    public static String getEncryRealFileName(Context ctx, String realFileName) {
        UserInfo currentUserInfo = ContextUtil.getCurrentUserInfo(ctx);
        return MessageFormat.format("{0}_{1}", realFileName, MD5.md5Hash(currentUserInfo.getId().toString()));
    }
    // -------------- 测试方法（一站式执行）--------------
//    public static void main(String[] args) {
//        // 1. 配置文件路径
//        String templatePath = "F:\\test/定调薪套打模板.docx"; // 原模板路径
//        String pdfOutputPath = "F:\\test/替换后的薪酬核定表PDF.pdf"; // 输出路径
//        // 2. 定义占位符-实际数据映射（同之前方案，可动态获取）
//        Map<String, String> dataMap = new HashMap<>();
//        // 基础信息
//        dataMap.put("T", "平级调薪");       // 异动类型
//        dataMap.put("X", "45602");          // 编码
//        dataMap.put("N", "技术岗");         // 员工类型（表格标题）
//        // 员工个人信息
//        dataMap.put("q", "李四");            // 员工姓名
//        dataMap.put("w", "EMP2024002");      // 工号
//        dataMap.put("e", "2024-02-20");      // 入职日期
//        dataMap.put("r", "大专");            // 学历
//        dataMap.put("t", "管理岗");          // 管理类别
//        dataMap.put("y", "研发二部");        // 所属组织
//        dataMap.put("u", "工程师");          // 职位
//        dataMap.put("i", "P4");              // 职级
//        // 工资结构
//        dataMap.put("A", "4000");            // 基本工资
//        dataMap.put("B", "1500");            // 加班工资
//        dataMap.put("C", "900");             // 技能工资
//        dataMap.put("J", "600");             // 岗位补贴
//        dataMap.put("E", "350");             // 学历补贴
//        dataMap.put("G", "10000");          // 月薪合计
//        dataMap.put("I", "月薪制");          // 工资类型
//        dataMap.put("F", "月薪制");          // 费用补贴
//        // 生效日期
//        dataMap.put("YYYYHHDD", "2024年08月15日");
//        try {
//            // 执行流程：替换占位符 → 转 PDF
//            batchReplaceWordPlaceholders(templatePath, pdfOutputPath, dataMap);
//            convertWordToPdf(pdfOutputPath, pdfOutputPath);
//
//            // 可选：删除临时 Word 文件（如需保留可注释）
////            File tempWordFile = new File(pdfOutputPath);
////            if (tempWordFile.exists()) {
////                tempWordFile.delete();
////                System.out.println("临时 Word 文件已删除");
////            }
//        } catch (Exception e) {
//            e.printStackTrace();
//            System.err.println("执行失败：" + e.getMessage());
//        }
//    }
}