package com.securitycontrol.common.core.utils;

import com.alibaba.fastjson2.JSONObject;
import com.securitycontrol.common.core.constant.Constant;
import com.securitycontrol.common.core.exception.ServiceException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ooxml.POIXMLDocumentPart;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.*;
import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTMarker;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author 10488
 * excel文件导入-包含图片
 */
@Slf4j
public class ImportExcelUtils {

    private static final List<String> PRONAME_LIST = new LinkedList<>();

    public static List<JSONObject> readExcel(MultipartFile file, Class<?> mClass, String uploadPath) throws Exception {
        String fileName = file.getOriginalFilename();
        log.info("OriginalFilename:{}", fileName);
        if (!StringUtils.endsWithAny(fileName, Constant.XLS, Constant.XLSX)) {
            throw new ServiceException("不支持excel以外的文件导入！");
        }
        List<JSONObject> list = new ArrayList<>();
        InputStream inputStream = file.getInputStream();
        String className = mClass.getSimpleName();
        log.info("className:{}", className);
        //根据指定的文件输入流导入Excel从而产生Workbook对象
        Workbook workbook = null;
        Sheet sheet = null;
        Map<String, PictureData> mapData = null;
        if (null != fileName && fileName.endsWith(Constant.XLS)) {
            workbook = new HSSFWorkbook(inputStream);
            //获取Excel文档中的第一个表单
            sheet = workbook.getSheetAt(0);
            if (!checkModal(sheet, className)) {
                throw new ServiceException("模板错误，请重新选择模板！");
            }
            mapData = getPicturesXls((HSSFSheet) sheet, className);
        }
        if (null != fileName && fileName.endsWith(Constant.XLSX)) {
            workbook = new XSSFWorkbook(inputStream);
            //获取Excel文档中的第一个表单
            sheet = workbook.getSheetAt(0);
            if (!checkModal(sheet, className)) {
                throw new ServiceException("模板错误，请重新选择模板！");
            }
            mapData = getPicturesXlsx((XSSFSheet) sheet, className);
        }
        List<Map<String, Object>> filenames = new ArrayList<>();
        if (Objects.equals(className, Constant.PRO_IMPORT_VO)) {
            log.info("开始读取并写入图片");
            filenames = writeImg(mapData, className, uploadPath);
            log.info("图片:{}，写入完成！", filenames);
        }
        int sheetCount = 0;
        if (workbook != null) {
            workbook.getNumberOfSheets();
        }
        log.info("Sheet(表单)数量：{}", sheetCount);
        log.info("filenames:{}", filenames);
        //获得最后一条记录得的行号，从0开始
        int totalRowNum = 0;
        if (sheet != null) {
            totalRowNum = sheet.getLastRowNum();
        }
        log.info("总记录数:{}", (totalRowNum + 1));
        list = createBean(sheet, mClass, filenames);
        inputStream.close();
        return list;
    }

    private static boolean checkModal(Sheet sheet, String className) {
        int colNum = sheet.getRow(0).getLastCellNum();
        if (Objects.equals(className, Constant.PRO_IMPORT_VO)) {
            return colNum == 25;
        }
        return false;
    }

    private static List<JSONObject> createBean(Sheet sheet, Class<?> mClass, List<Map<String, Object>> filename) throws Exception {
        if (sheet == null || sheet.getLastRowNum() < 0) {
            return null;
        }
        List<JSONObject> list = new ArrayList<>();
        // 总列数
        int last = sheet.getRow(0).getLastCellNum();
        log.info("列数:{}", last);
        try {
            for (Row row : sheet) {
                if (row == null) {
                    continue;
                }
                // 第一行是标题栏
                if (Objects.equals(mClass.getSimpleName(), Constant.PRO_IMPORT_VO)) {
                    if (row.getRowNum() < 2) {
                        continue;
                    }
                }
                boolean isBlankRow = true;
                for (Cell c : row) {
                    if (c.getCellType() != CellType.BLANK) {
                        isBlankRow = false;
                        break;
                    }
                }
                if (isBlankRow) {
                    continue;
                }
                JSONObject obj = new JSONObject();
                obj.put("rowNo", row.getRowNum() + 1);
                if (Objects.equals(mClass.getSimpleName(), Constant.PRO_IMPORT_VO)) {
                    setExcelToString(18, row);
                    obj = setProObjData(row, obj, filename);
                }
                list.add(obj);
            }
        } catch (IllegalStateException e) {
            e.printStackTrace();
            throw new ServiceException("模板中含有单元格数据格式不正确");
        }
        return list;
    }

    /**
     * 工程数据赋值
     *
     * @param row
     * @param obj
     * @return JSONObject
     * @description
     * @author cwchen
     * @date 2024/3/12 15:09
     */
    public static JSONObject setProObjData(Row row, JSONObject obj, List<Map<String, Object>> files) {
        if (row.getCell(Constant.CELL_1) != null) {
            // 建管单位
            obj.put("org", row.getCell(Constant.CELL_1).getStringCellValue());
        }
        if (row.getCell(Constant.CELL_2) != null) {
            // 工程名称
            obj.put("proName", row.getCell(Constant.CELL_2).getStringCellValue());
        }
        if (row.getCell(Constant.CELL_3) != null) {
            // 工程类型
            obj.put("proType", row.getCell(Constant.CELL_3).getStringCellValue());
        }
        if (row.getCell(Constant.CELL_4) != null) {
            // 工程编码
            obj.put("proCode", row.getCell(Constant.CELL_4).getStringCellValue());
        }
        if (row.getCell(Constant.CELL_5) != null) {
            // 工程状态
            obj.put("status", row.getCell(Constant.CELL_5).getStringCellValue());
        }
        if (row.getCell(Constant.CELL_6) != null) {
            // 单项编码
            obj.put("signCode", row.getCell(Constant.CELL_6).getStringCellValue());
        }
        if (row.getCell(Constant.CELL_7) != null) {
            // 标段编码
            obj.put("bidCode", row.getCell(Constant.CELL_7).getStringCellValue());
        }
        if (row.getCell(Constant.CELL_8) != null) {
            // 规模
            obj.put("proScale", row.getCell(Constant.CELL_8).getStringCellValue());
        }
        if (row.getCell(Constant.CELL_9) != null) {
            // 监理单位
            obj.put("jlUnit", row.getCell(Constant.CELL_9).getStringCellValue());
        }
        if (row.getCell(Constant.CELL_10) != null) {
            // 施工单位
            obj.put("sgUnit", row.getCell(Constant.CELL_10).getStringCellValue());
        }
        if (row.getCell(Constant.CELL_11) != null) {
            // 项目经理
            obj.put("manager", row.getCell(Constant.CELL_11).getStringCellValue());
        }
        if (row.getCell(Constant.CELL_12) != null) {
            // 计划开始时间
            obj.put("planStartTime", row.getCell(Constant.CELL_12).getStringCellValue());
        }
        if (row.getCell(Constant.CELL_13) != null) {
            // 计划结束时间
            obj.put("planEndTime", row.getCell(Constant.CELL_13).getStringCellValue());
        }
        if (row.getCell(Constant.CELL_14) != null) {
            // 实际开始时间
            obj.put("startTime", row.getCell(Constant.CELL_14).getStringCellValue());
        }
        if (row.getCell(Constant.CELL_15) != null) {
            // 实际结束时间
            obj.put("endTime", row.getCell(Constant.CELL_15).getStringCellValue());
        }
        if (row.getCell(Constant.CELL_16) != null) {
            // 项目总成本（万）
            obj.put("proCost", row.getCell(Constant.CELL_16).getStringCellValue());
        }
        if (row.getCell(Constant.CELL_17) != null) {
            // 工程简介
            obj.put("proBrief", row.getCell(Constant.CELL_17).getStringCellValue());
        }
        if (row.getCell(Constant.CELL_18) != null) {
            // 工程阶段
            obj.put("bidType", row.getCell(Constant.CELL_18).getStringCellValue());
        }
        if (row.getCell(Constant.CELL_19) != null) {
            // 施工项目经理
            obj.put("sgManage", row.getCell(Constant.CELL_19).getStringCellValue());
        }
        if (row.getCell(Constant.CELL_20) != null) {
            // 监理工程师
            obj.put("jlManage", row.getCell(Constant.CELL_20).getStringCellValue());
        }
        if (row.getCell(Constant.CELL_21) != null) {
            // 变电站类型包括:1 土建,2 电气,3 变电
            obj.put("subType", row.getCell(Constant.CELL_21).getStringCellValue());
        }
        if (row.getCell(Constant.CELL_22) != null) {
            // 投产时间
            obj.put("tcDate", row.getCell(Constant.CELL_22).getStringCellValue());
        }
        obj = setFileObj(row, obj, files);
        return obj;
    }

    public static JSONObject setFileObj(Row row, JSONObject obj, List<Map<String, Object>> files) {
        // 平面图
        String fileName = "file" + "_" + row.getRowNum() + "_1";
        for (Map<String, Object> map : files) {
            for (String keyName : map.keySet()) {
                if (Objects.equals(fileName, keyName)) {
                    obj.put("file", map.get(keyName));
                }
            }
        }
        // 图片1
        String fileName2 = "file" + "_" + row.getRowNum() + "_2";
        for (Map<String, Object> map : files) {
            for (String keyName : map.keySet()) {
                if (Objects.equals(fileName2, keyName)) {
                    obj.put("file2", map.get(keyName));
                }
            }
        }
        // 图片2
        String fileName3 = "file" + "_" + row.getRowNum() + "_3";
        for (Map<String, Object> map : files) {
            for (String keyName : map.keySet()) {
                if (Objects.equals(fileName3, keyName)) {
                    obj.put("file3", map.get(keyName));
                }
            }
        }
        // 图片3
        String fileName4 = "file" + "_" + row.getRowNum() + "_4";
        for (Map<String, Object> map : files) {
            for (String keyName : map.keySet()) {
                if (Objects.equals(fileName4, keyName)) {
                    obj.put("file4", map.get(keyName));
                }
            }
        }
        // 图片4
        String fileName5 = "file" + "_" + row.getRowNum() + "_5";
        for (Map<String, Object> map : files) {
            for (String keyName : map.keySet()) {
                if (Objects.equals(fileName5, keyName)) {
                    obj.put("file5", map.get(keyName));
                }
            }
        }
        // 图片3
        String fileName6 = "file" + "_" + row.getRowNum() + "_6";
        for (Map<String, Object> map : files) {
            for (String keyName : map.keySet()) {
                if (Objects.equals(fileName6, keyName)) {
                    obj.put("file6", map.get(keyName));
                }
            }
        }
        // 图片3
        String fileName7 = "file" + "_" + row.getRowNum() + "_7";
        for (Map<String, Object> map : files) {
            for (String keyName : map.keySet()) {
                if (Objects.equals(fileName7, keyName)) {
                    obj.put("file7", map.get(keyName));
                }
            }
        }
        return obj;
    }

    /**
     * 获取图片和位置 (xlsx)
     *
     * @param sheet
     * @return
     * @throws IOException
     */
    public static Map<String, PictureData> getPicturesXlsx(XSSFSheet sheet, String className) throws IOException {
        Map<String, PictureData> map = new HashMap<>(16);
        List<POIXMLDocumentPart> list = sheet.getRelations();
        for (POIXMLDocumentPart part : list) {
            if (part instanceof XSSFDrawing) {
                XSSFDrawing drawing = (XSSFDrawing) part;
                List<XSSFShape> shapes = drawing.getShapes();

                for (XSSFShape shape : shapes) {
                    XSSFPicture picture = (XSSFPicture) shape;
                    XSSFClientAnchor anchor = picture.getPreferredSize();
                    CTMarker marker = anchor.getFrom();
                    Row row = sheet.getRow(marker.getRow());
                    if (row == null) {
                        continue;
                    }
                    String keyName = null;
                    if (Objects.equals(className, Constant.PRO_IMPORT_VO)) {
                        keyName = setKey(picture, row, Constant.PRO_IMPORT_VO);
                    } else {
                        keyName = "";
                    }
                    map.put(keyName, picture.getPictureData());
                }
            }
        }
        return map;
    }

    /**
     * 获取图片和位置 (xls)
     *
     * @param sheet
     * @return
     * @throws IOException
     */
    public static Map<String, PictureData> getPicturesXls(HSSFSheet sheet, String className) throws IOException {
        int i = 0;
        Map<String, PictureData> map = new HashMap<String, PictureData>(16);
        if (sheet.getDrawingPatriarch() != null) {
            List<HSSFShape> list = sheet.getDrawingPatriarch().getChildren();
            for (HSSFShape shape : list) {
                if (shape instanceof HSSFPicture) {
                    HSSFPicture picture = (HSSFPicture) shape;
                    int pictureIndex = ((HSSFPicture) shape).getPictureIndex();
                    if (pictureIndex != -1) {
                        HSSFClientAnchor cAnchor = picture.getClientAnchor();
                        Row row = sheet.getRow(cAnchor.getRow1());
                        if (row == null) {
                            continue;
                        }
                        String keyName = null;
                        if (cAnchor.getCol1() == 23) {
                            PRONAME_LIST.add(row.getCell(1).getStringCellValue());
                            keyName = "file" + "_" + cAnchor.getRow1() + "_1";
                        } else if (cAnchor.getCol1() == 24) {
                            PRONAME_LIST.add(row.getCell(1).getStringCellValue());
                            keyName = "file" + "_" + cAnchor.getRow1() + "_2";
                        } else if (cAnchor.getCol1() == 25) {
                            PRONAME_LIST.add(row.getCell(1).getStringCellValue());
                            keyName = "file" + "_" + cAnchor.getRow1() + "_3";
                        } else if (cAnchor.getCol1() == 26) {
                            PRONAME_LIST.add(row.getCell(1).getStringCellValue());
                            keyName = "file" + "_" + cAnchor.getRow1() + "_4";
                        } else if (cAnchor.getCol1() == 27) {
                            PRONAME_LIST.add(row.getCell(1).getStringCellValue());
                            keyName = "file" + "_" + cAnchor.getRow1() + "_5";
                        } else if (cAnchor.getCol1() == 28) {
                            PRONAME_LIST.add(row.getCell(1).getStringCellValue());
                            keyName = "file" + "_" + cAnchor.getRow1() + "_6";
                        } else if (cAnchor.getCol1() == 29) {
                            PRONAME_LIST.add(row.getCell(1).getStringCellValue());
                            keyName = "file" + "_" + cAnchor.getRow1() + "_7";
                        }
                        map.put(keyName, picture.getPictureData());
                    }
                }
            }
        }
        return map;
    }

    /**
     * 图片写出
     */
    public static List<Map<String, Object>> writeImg(Map<String, PictureData> mapData, String className, String uploadPath) throws IOException {
        if (mapData == null || mapData.size() == 0) {
            return new ArrayList<>();
        }
        Object[] keyArr = mapData.keySet().toArray();
        ArrayList<Map<String, Object>> filename = new ArrayList<>();
        for (int i = 0; i < mapData.size(); i++) {
            Map<String, Object> map = new HashMap<>(16);
            // 获取图片流
            PictureData pic = mapData.get(keyArr[i]);
            // 获取图片索引
            String picName = keyArr[i].toString();
            byte[] data = pic.getData();
            MultipartFile multipartFile = BytesToMultipartFileUtil.encodeToMultipartFile(data, uploadPath);
            map.put(picName + "", multipartFile);
            filename.add(map);
        }
        return filename;
    }


    private static String setKey(XSSFPicture picture, Row row, String className) {
        if (row == null) {
            return null;
        }
        ;
        String result = picture.getPreferredSize().toString();
        String pattern = "\\<xdr\\:col\\>[1-9]\\d*\\<\\/xdr\\:col\\>";
        Pattern r = Pattern.compile(pattern);
        String col = "";
        Matcher m = r.matcher(result);
        if (m.find()) {
            col = m.group(0);
        } else {
            System.out.println("NO MATCH");
        }

        if (Objects.equals(className, Constant.PRO_IMPORT_VO)) {
            switch (col) {
                case "<xdr:col>23</xdr:col>":
                    return "file" + "_" + row.getRowNum() + "_1";
                case "<xdr:col>24</xdr:col>":
                    return "file" + "_" + row.getRowNum() + "_2";
                case "<xdr:col>25</xdr:col>":
                    return "file" + "_" + row.getRowNum() + "_3";
                case "<xdr:col>26</xdr:col>":
                    return "file" + "_" + row.getRowNum() + "_4";
                case "<xdr:col>27</xdr:col>":
                    return "file" + "_" + row.getRowNum() + "_5";
                case "<xdr:col>28</xdr:col>":
                    return "file" + "_" + row.getRowNum() + "_6";
                case "<xdr:col>29</xdr:col>":
                    return "file" + "_" + row.getRowNum() + "_7";
                default:
                    return null;
            }
        } else {
            return "";
        }

    }

    private static void setExcelToString(int j, Row row) {

        for (int i = 0; i < j; i++) {
            if (row.getCell(i) != null) {
                row.getCell(i).setCellType(CellType.STRING);
            }
        }
    }
}
