package com.ruoyi.common.importExcel.utils;


import com.ruoyi.common.exception.ServiceErrorException;
import com.ruoyi.common.importExcel.annotation.ExcelSheetDataValidation;
import com.ruoyi.common.importExcel.excel.TableTypeEnum;
import com.ruoyi.common.importExcel.excel.helper.BasicExcelHelper;
import com.ruoyi.common.importExcel.excel.validation.BasicDataValidation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.DataValidation;
import org.apache.poi.ss.usermodel.DataValidationConstraint;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.util.CellRangeAddressList;
import org.apache.poi.ss.util.CellReference;
import org.apache.poi.util.Units;
import org.apache.poi.xssf.usermodel.XSSFDataValidationHelper;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.xwpf.usermodel.*;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.net.URLEncoder;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;

@Slf4j
@Component
public class FileUtils {

    public final static String ExcelTemplatePath = "excelTemplate/";

//    public void downloadTemplateWord(HttpServletRequest request, HttpServletResponse response, String fileName, Map<String, Object> data, List< Map<String, Object>> list, Map<Integer,String> keyMap ) {
//        try {
//            ClassPathResource classPathResource = new ClassPathResource(ExcelTemplatePath + fileName);
//            InputStream inputStream = classPathResource.getInputStream();
//
//            response.addHeader("Content-Disposition",
//                    "attachment;filename=" + URLEncoder.encode(fileName.replace(".docx", data.get("${contractNo}").toString() + ".pdf"), "UTF-8"));
//            response.setHeader("Access-Control-Allow-Origin", request.getHeader("origin"));
//            response.setHeader("Access-Control-Allow-Credentials", "true");
//            response.addHeader("Access-Control-Expose-Headers", "Content-Disposition");
//
//            OutputStream outputStream = response.getOutputStream();
//            response.setContentType("application/octet-stream");
//
//            // 写入额外数据
//            wordConverterToPdf(inputStream, outputStream, data,list,keyMap);
//            outputStream.flush();
//            inputStream.close();
//            outputStream.close();
//        } catch (Exception e) {
//            e.printStackTrace();
//            throw new ServiceErrorException("下载失败");
//        }
//    }

    /**
     * 将word文档， 转换成pdf, 中间替换掉变量
     * @param source 源为word文档， 必须为docx文档
     * @param target 目标输出
     * @param params 需要替换的变量
     * @throws Exception
     */
//    public static void wordConverterToPdf(InputStream source,
//                                          OutputStream target, Map<String, Object> params,List<Map<String, Object>> list,Map<Integer,String> keyMap) throws Exception {
//        wordConverterToPdf(source, target, null, params,list,keyMap);
//    }

    /**
     * 将word文档， 转换成pdf, 中间替换掉变量
     * @param source 源为word文档， 必须为docx文档
     * @param target 目标输出
     * @param params 需要替换的变量
     * @param options PdfOptions.create().fontEncoding( "windows-1250" ) 或者其他
     * @throws Exception
     */
//    public static void wordConverterToPdf(InputStream source, OutputStream target,
//                                          PdfOptions options,
//                                          Map<String, Object> params,
//                                          List<Map<String, Object>> list,
//                                          Map<Integer,String> keyMap ) throws Exception {
//        XWPFDocument doc = new XWPFDocument(source);
//        replaceWordText(doc.getParagraphs(), params);
//        for (XWPFHeader heads: doc.getHeaderList()){
//           replaceWordText(heads.getParagraphs(),params);
//            //replaceWordTextFootHead(heads.getParagraphs(),params,"head");
//        }
//        for (XWPFFooter footer: doc.getFooterList()){
//           replaceWordText(footer.getParagraphs(),params);
//            //replaceWordTextFootHead(footer.getParagraphs(),params,"foot");
//        }
//
//        int t = 0;
//        for (XWPFTable table : doc.getTables()) {
//            //表3=为附件 r = 2
//            //记录列id
//            int r = 0;
//            for (XWPFTableRow row : table.getRows()) {
//                int c = 0;
//                for (XWPFTableCell cell : row.getTableCells()) {
//                    if(t==2){
//                        if(r>1&&r<=list.size()){
//                            replaceWordTextSpecical(cell.getParagraphs(),list.get(r-1),keyMap.get(c));
//                        }else {
//                            replaceWordText(cell.getParagraphs(), list.get(0));
//                        }
//
//                    }else{
//                        replaceWordText(cell.getParagraphs(), params);
//                    }
//                    c++;
//                }
//                r++;
//            }
//            t++;
//        }
//        PdfConverter.getInstance().convert(doc, target, options);
//    }

    /** 替换段落中内容 */
    private static void paragraphReplace(List<XWPFParagraph> paragraphs, Map<String, String> params) {
        if (MapUtils.isNotEmpty(params)) {
            for (XWPFParagraph p : paragraphs){
                for (XWPFRun r : p.getRuns()){
                    String content = r.getText(r.getTextPosition());
                    if(StringUtils.isNotEmpty(content) && params.containsKey(content)) {
                        r.setText(params.get(content), 0);
                    }
                }
            }
        }
    }

    //赋值指定行
    private static void replaceWordTextSpecical(List<XWPFParagraph> paragraphList, Map<String, Object> param, String key) throws IOException, InvalidFormatException {
        for (XWPFParagraph paragraph : paragraphList) {
            // 新建runs
            if(!StringUtils.isEmpty(key)&&param.containsKey(key)){
                String rs = "";
                if(!ObjectUtils.isEmpty(param.get(key))){
                    rs = param.get(key).toString();
                }
                paragraph.insertNewRun(0).setText(rs);
            }
        }
    }

    private static void replaceWordTextFootHead(List<XWPFParagraph> paragraphList, Map<String, Object> param, String key) throws IOException, InvalidFormatException {
        for (XWPFParagraph paragraph : paragraphList) {
            // 遍历获取段落中所有的runs
            List<XWPFRun> runs = paragraph.getRuns();
            if(runs.size()==0){
                if("head".equals(key)){
                    paragraph.insertNewRun(0).setText("合同编号：");
                }else {
                    paragraph.insertNewRun(0).setText("页码");
                }
            }else {
                replaceWordText(paragraphList,param);
            }

        }
    }


    private static void replaceWordText(List<XWPFParagraph> paragraphList, Map<String, Object> param) throws IOException, InvalidFormatException {
        for (XWPFParagraph paragraph : paragraphList) {
            // 遍历获取段落中所有的runs
            List<XWPFRun> runs = paragraph.getRuns();
            // 合并逻辑
            for (int i = 0; i < runs.size(); i++) {
                //获取字符
                String text0 = runs.get(i).getText(runs.get(i).getTextPosition());
                if (text0 != null && text0.contains("$")) {
                    //包含占位符的字符缓存
                    StringBuilder cache = new StringBuilder(text0);
                    //记录run结束的角标，开始的角标为i
                    int endIndex = 0;
                    boolean contains = text0.contains("}");
                    //同一个run中是否包含完成占位符
                    if (!contains) {
                        int j = i + 1;
                        for (; j < runs.size(); j++) {
                            String text1 = runs.get(j).getText(runs.get(j).getTextPosition());
                            if (text1 == null) {
                                continue;
                            }
                            cache.append(text1);
                            if (text1.contains("}")) {
                                endIndex = j;
                                break;
                            }
                        }
                    }
                    if (contains || endIndex != 0) {
                        //处理替换
                        String s = cache.toString();
                        for (Map.Entry<String, Object> entry : param.entrySet()) {
                            String k = entry.getKey();
                            if (!s.contains(k)) continue;
                            Object value = entry.getValue();
                            if (value instanceof String) {
                                String replace = s.replace(k, value.toString());
                                runs.get(i).setText(replace, 0);
                            } else if (value instanceof InputStream){
                                runs.get(i).setText("", 0);
                                runs.get(i).addPicture((InputStream) value, XWPFDocument.PICTURE_TYPE_PNG, "sign.png", Units.toEMU(100), Units.toEMU(50));
                            } else {
                                runs.get(i).setText("", 0);
                            }
                            for (int j = endIndex; j > i; j--) {
                                paragraph.removeRun(j);
                            }
                            break;
                        }
                    }
                }
            }
        }
    }


    public void downloadTemplate(HttpServletRequest request, HttpServletResponse response, String fileName, List<List<? extends BasicExcelHelper>> data, BasicDataValidation validations) {
        try {
            ClassPathResource classPathResource = new ClassPathResource(ExcelTemplatePath + fileName);
            InputStream inputStream = classPathResource.getInputStream();

            String downloadName = Objects.nonNull(request.getAttribute("downloadName")) ? (String) request.getAttribute("downloadName"): classPathResource.getFilename();
            //response.addHeader("Content-Disposition","attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
            response.addHeader("Content-Disposition","attachment;filename=" + URLEncoder.encode(downloadName, "UTF-8"));
            response.setHeader("Access-Control-Allow-Origin", request.getHeader("origin"));
            response.setHeader("Access-Control-Allow-Credentials", "true");
            response.addHeader("Access-Control-Expose-Headers", "Content-Disposition");

            OutputStream outputStream = new BufferedOutputStream(response.getOutputStream());
            response.setContentType("application/octet-stream");

            // 写入额外数据
            if (CollectionUtils.isNotEmpty(data)) {
                XSSFWorkbook workbook = new XSSFWorkbook(inputStream);
                // 基础表用于存放校验数据
                XSSFSheet baseSheet = workbook.getSheetAt(0);
                XSSFRow baseRow = baseSheet.getRow(0);
                for (int i = 0; i < data.size(); i++) {
                    XSSFSheet sheet = workbook.getSheetAt(i);

                    // 1. 填充数据
                    ExcelUtils.writeData(sheet, data.get(i));

                    // 2. 设置校验(跳过第一个基本信息sheet)
                    if (Objects.nonNull(validations) && i > 0) {
                        List<Field> fields = Arrays.asList(validations.getClass().getDeclaredFields());
                        for (Field field : fields) {
                            ExcelSheetDataValidation validateInfo = field.getAnnotation(ExcelSheetDataValidation.class);
                            if (Objects.isNull(validateInfo)) {
                                continue;
                            }
                            XSSFDataValidationHelper dvHelper = new XSSFDataValidationHelper(sheet);
                            List<String> validationData = (List<String>) Reflections.invokeGetter(validations, field.getName());
                            if (CollectionUtils.isEmpty(validationData)) {
                                continue;
                            }
                            // 将校验数据依次存入基础表
                            int cellNum = baseRow.getLastCellNum();
                            for (int j=0;j<validationData.size();j++){
                                Row row = baseSheet.getRow(j);
                                if (Objects.isNull(row)){
                                    row = baseSheet.createRow(j);
                                }
                                Cell cell = row.getCell(cellNum);
                                if (Objects.isNull(cell)){
                                    cell = row.createCell(cellNum);
                                }
                                cell.setCellValue(validationData.get(j));
                            }
                            String colName =  "$" + CellReference.convertNumToColString(cellNum) + "$";
                            String formula = baseSheet.getSheetName() + "!" + colName + "1:" + colName + validationData.size();
                            DataValidationConstraint constraint = dvHelper.createFormulaListConstraint(formula);
                            for (int j = 0; j < validateInfo.col().length; j++) {
                                int col = validateInfo.col()[j];
                                CellRangeAddressList cellRangeAddressList = validateInfo.isWholeCol() ?
                                        new CellRangeAddressList(validateInfo.rowStart(), 1000, col, col)
                                        : new CellRangeAddressList(validateInfo.row(), validateInfo.row(), col, col);
                                DataValidation dataValidation = dvHelper.createValidation(constraint, cellRangeAddressList);
                                dataValidation.setShowErrorBox(true);
                                dataValidation.createErrorBox("错误", "不支持的选项，请从当前下拉框中选择");
                                sheet.addValidationData(dataValidation);
                            }
                        }
                    }
                }
                workbook.write(outputStream);
            } else {
                byte[] buffer = new byte[inputStream.available()];
                inputStream.read(buffer);
                outputStream.write(buffer);
            }
            outputStream.flush();
            inputStream.close();
            outputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
            throw new ServiceErrorException("下载失败");
        }
    }

    public void downloadTemplate(HttpServletRequest request, HttpServletResponse response, String fileName) {
        downloadTemplate(request, response, fileName, null);
    }

    public void downloadTemplate(HttpServletRequest request, HttpServletResponse response, String fileName, List<List<? extends BasicExcelHelper>> data) {
        downloadTemplate(request, response, fileName, data, null);
    }


    //public String getFileNames(TableTypeEnum tableTypeEnum, Locale locale) {
    //    String language = locale.getLanguage();
    //
    //    String path = tableTypeEnum.getPath();
    //
    //    // 获取文件名
    //    try {
    //
    //        File directory;
    //        String returnPath = "";
    //        try {
    //            URL url = new ClassPathResource(ExcelTemplatePath + path + "/" + language).getURL();
    //            String string = url.toString();
    //            log.info("【模板导出】在当前路径：{}下查找文件", string);
    //            
    //            //ClassPathResource classPathResource = new ClassPathResource(ExcelTemplatePath + path + "/" + language);
    //            directory = new File(new ClassPathResource(ExcelTemplatePath + path + "/" + language).getURL().getFile());
    //
    //          
    //
    //            //directory = new ClassPathResource(ExcelTemplatePath + path + "/" + language).getFile();
    //            log.info("【模板导出】在当前路径：{}下查找文件", ExcelTemplatePath + path + "/" + language);
    //            
    //            log.info("【模板导出】directory：{}", directory);
    //            log.info("【模板导出】文件夹是否存在：{}", directory.exists());
    //
    //            if (directory.isDirectory() && ArrayUtils.isEmpty(directory.listFiles())) {
    //                log.info("【模板导出】存在国际化文件夹，但是文件夹为空，查找根路径下文件：{}", tableTypeEnum.getName());
    //                //directory = new ClassPathResource(ExcelTemplatePath).getFile();
    //                directory = new File(new ClassPathResource(ExcelTemplatePath).getURL().getFile());
    //                returnPath = "";
    //            } else {
    //                returnPath = path + "/" + language;
    //            }
    //            log.info("returnPath: {}", returnPath);
    //        } catch (FileNotFoundException e) {
    //            // 没有国际化文件夹时，可能不需要国际化，直接在设定根路径下查找
    //            log.info("【模板导出】没有国际化文件夹时，可能不需要国际化，直接在设定根路径下查找文件： {}", tableTypeEnum.getName());
    //            //directory = new ClassPathResource(ExcelTemplatePath + path).getFile();
    //            directory = new File(new ClassPathResource(ExcelTemplatePath + path).getURL().getFile());
    //        }
    //
    //        if (directory.isDirectory()) {
    //            // 获取目录中的所有文件和子目录
    //            File[] files = directory.listFiles();
    //            log.info("【模板导出】文件夹下文件个数：{}", files.length);
    //
    //            if (ArrayUtils.isNotEmpty(files)) {
    //                for (File file : files) {
    //                    log.info("【模板导出】文件名：{}", file.getName());
    //                    if (file.isFile()) {
    //                        System.out.println("File: " + file.getName());
    //                        //return returnPath + "/" + file.getName();
    //                        if (com.ruoyi.common.utils.StringUtils.isEmpty(returnPath)) {
    //                            // 文件名去掉后缀
    //                            String fName = file.getName().substring(0, file.getName().lastIndexOf("."));
    //                            if (tableTypeEnum.getName().equals(fName)) {
    //                                return file.getName();
    //                            }
    //                        } else {
    //                            return returnPath + "/" + file.getName();
    //                        }
    //                    }
    //                }
    //            }
    //            log.error("【模板导出】Expected a file, found a directory: {}", directory.getName());
    //            throw new IOException("Expected a file, found a directory: " + directory.getName());
    //        } else {
    //            log.error("【模板导出】Expected a directory, found a file: {}", directory.getName());
    //            throw new IOException("Expected a directory, found a file: " + directory.getName());
    //        }
    //
    //    } catch (FileNotFoundException e) {
    //        e.printStackTrace();
    //        throw new RuntimeException("当前文件路径下没有文件: " + ExcelTemplatePath + path + "/" + language + "||" + e.getMessage());
    //    } catch (IOException e) {
    //        throw new RuntimeException(e);
    //    }
    //}
}
