package com.xhkjedu.sexam.utils;

import com.xhkjedu.sexam.model.paperstudent.EPsqbatchDetail;
import com.xhkjedu.sexam.vo.paperstudent.EPsqbatchStuVo;
import com.xhkjedu.utils.N_Utils;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.io.InputStream;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author ywx
 * @classname PoiUtils
 * @description
 * @date 2022-11-21 14:46:22
 **/
@Component
@Slf4j
public class PoiUtils {
    //2003- 版本的excel
    private final static String excel2003L = ".xls";
    //2007+ 版本的excel
    private final static String excel2007U = ".xlsx";

    /**
     * 导入教师
     *
     * @return java.util.Map<java.lang.String, java.lang.Object>
     * @Param [file]
     * @Author ywx
     * @Date 2022/3/17 9:44
     **/
    public static Map<String, Object> readExcelRecord(MultipartFile file, List<Map> qns, List<Map> students
            , List<Map> classes) throws Exception {
        Map<String, Object> resultMap = new HashMap<>();
        Map<Integer, List<String>> errMsg = new LinkedHashMap<>();
        try {
            // 数据校验
            isExcelEmpty(file);
            InputStream in = file.getInputStream();
            String fileName = file.getOriginalFilename();
            Workbook work = getWorkbook(in, fileName);
            Sheet sheet;// 分表数据
            Row row;// 行数据
            sheet = work.getSheetAt(0);//只取第一个sheet
            if (sheet == null) {
                throw new Exception("Excel第一个分表内容为空！");
            }

            int rows = sheet.getLastRowNum(); // 获取最后一个实际行的下标，比行数小1
            int firstRowNum = sheet.getFirstRowNum(); // 获取第一个实际行的下标，（firstRowNum=0）
            row = sheet.getRow(firstRowNum);//标题行
            int firstCellNum = row.getFirstCellNum();
            int lastCellNum = row.getLastCellNum();// 每一行的最后一列，获取列数，比最后一列列标大1
            String qn = qns.stream().map(q -> q.get("qn").toString()).collect(Collectors.joining());
            Map<Integer, Integer> questionMap = new HashMap<>();
            Map<Integer, Double> scoreMap = new HashMap<>();
            for (int i = 0; i < qns.size(); i++) {
                questionMap.put(i + 2, (Integer) qns.get(i).get("eptqid"));
                scoreMap.put(i + 2, (Double) qns.get(i).get("score"));
            }
            String titleName = "姓名班级" + qn;//标题格式
            StringBuilder sb = new StringBuilder();
            for (int y = firstCellNum; y < lastCellNum; y++) {
                sb.append(row.getCell(y));
            }
            int maxIndex = lastCellNum - 1;//最大题号下标
            String importTitleName = sb.toString();
            if (!titleName.equals(importTitleName)) throw new Exception("标题格式不正确");

            Map<Object, String> classMap = classes.stream().collect(Collectors.toMap(
                    c -> c.get("classid"), c -> c.get("classname").toString()));

            for (Map s : students) {
                s.put("classname", classMap.get(s.get("classid")));
            }

            // 导入记录信息
            List<EPsqbatchStuVo> stus = new ArrayList<>();

            Row trow = sheet.getRow(firstRowNum);//第一行为标题头
            //遍历当前sheet中的所有行 排除第一行  第一行为标题头 不纳入遍历
            for (int x = firstRowNum + 1; x <= rows; x++) {
                // 获取行
                row = sheet.getRow(x);
                if (row == null) {//若此行为空，则跳出循环继续下一行
                    continue;
                } else if (isEmptyCell(row.getCell(0)) && isEmptyCell(row.getCell(1))) {
                    continue;
                }
                firstCellNum = row.getFirstCellNum();// 每一行的第一列，（firstCellNum=0）
                if (firstCellNum == 1) throw new Exception("第" + (x + 1) + "行姓名不能为空");
                lastCellNum = row.getLastCellNum();// 每一行的最后一列，获取列数，比最后一列列标大1
                List<String> mrows = new ArrayList<>();
                //遍历所有的列
                String username = getCellValue(row.getCell(0));//姓名
                String classname = getCellValue(row.getCell(1));//班级
                Integer studentid = null;
                List<Map> list;
                if (N_Utils.isEmpty(classname)) {
                    list = students.stream().filter(s -> username.equals(s.get("username").toString())).collect(Collectors.toList());
                    if (N_Utils.isListEmpty(list) || list.size() > 1) {
                        mrows.add("学生【" + username + "】班级不能为空");
                        errMsg.put(x + 1, mrows);
                        continue;//学生不存在处理下一行
                    } else {
                        studentid = (Integer) list.get(0).get("studentid");
                    }
                } else {
                    list = students.stream().filter(s -> username.equals(s.get("username").toString())
                            && classname.equals(s.get("classname").toString())).collect(Collectors.toList());
                    if (N_Utils.isListEmpty(list)) {
                        mrows.add("学生【" + username + "（" + classname + "）】不存在");
                        errMsg.put(x + 1, mrows);
                        continue;//学生不存在处理下一行
                    } else if (list.size() > 1) {
                        mrows.add("学生【" + username + "（" + classname + "）】存在多个");
                        errMsg.put(x + 1, mrows);
                        continue;//学生不存在处理下一行
                    } else {
                        studentid = (Integer) list.get(0).get("studentid");
                    }
                }

                List<EPsqbatchDetail> details = new ArrayList<>();
                for (int y = firstCellNum + 2; y < lastCellNum; y++) {
                    Cell cell = row.getCell(y);
                    String score = getCellValue(cell);
                    if (N_Utils.isEmpty(score) && y == maxIndex && N_Utils.isListNotEmpty(mrows)) {
                        errMsg.put(x + 1, mrows);
                        continue;
                    } else if (N_Utils.isEmpty(score)) {
                        continue;//学生分值为空处理下一列
                    }
                    EPsqbatchDetail detail = new EPsqbatchDetail();
                    Double stuscore = Double.valueOf(score);
                    Double qscore = scoreMap.get(y);
                    if (Double.compare(stuscore, qscore) == 1) {
                        //stuscore = qscore;
                        mrows.add(trow.getCell(y) + "满分" + ExamUtil.doubleToStr(qscore) + "分，导入为" + ExamUtil.doubleToStr(stuscore) + "分");
                        errMsg.put(x + 1, mrows);
                        continue;//学生不存在处理下一行
                    }
                    detail.setNewscore(stuscore);
                    detail.setEptqid(questionMap.get(y));
                    details.add(detail);
                    if (y == maxIndex && N_Utils.isListNotEmpty(mrows)) {
                        errMsg.put(x + 1, mrows);
                    }
                }
                if (N_Utils.isListNotEmpty(details)) {
                    EPsqbatchStuVo stu = new EPsqbatchStuVo();
                    stu.setStudentid(studentid);
                    stu.setDetails(details);
                    stus.add(stu);
                }
            }

            resultMap.put("code", 0);
            resultMap.put("stus", stus);
        } catch (Exception e) {
            resultMap.put("code", 1);
            String msg = e.getMessage();
            if (N_Utils.isEmpty(msg)) msg = "读取报错";
            resultMap.put("msg", msg);
            if (msg.contains("Invalid ")) {
                msg = "格式不正确";
            }
            throw new Exception(msg);
        }
        resultMap.put("errMsg", errMsg);
        return resultMap;
    }

    /**
     * 根据文件后缀，自适应上传文件的版本
     *
     * @return org.apache.poi.ss.usermodel.Workbook
     * @Param [inStr, fileName]
     * @Author ywx
     * @Date 2020/6/3 16:42
     **/
    public static Workbook getWorkbook(InputStream inStr, String fileName) throws Exception {
        Workbook wb;
        String fileType = fileName.substring(fileName.lastIndexOf("."));
        if (excel2003L.equals(fileType)) {
            wb = new HSSFWorkbook(inStr);  //2003-
        } else if (excel2007U.equals(fileType)) {
            wb = new XSSFWorkbook(inStr);  //2007+
        } else {
            throw new Exception("Excel格式解析有误！");
        }
        return wb;
    }

    /**
     * 判断单元格是否是空值
     *
     * @return java.lang.Boolean
     * @Param [cell]
     * @Author ywx
     * @Date 2020/6/3 16:37
     **/
    public static Boolean isEmptyCell(Cell cell) {
        if (cell != null) {
            Boolean rtn = true;
            if (N_Utils.isNotEmpty(PoiUtils.getCellValue(cell))) {
                rtn = false;
            }
            return rtn;
        } else {
            return true;
        }
    }

    /**
     * 对表格中数值进行格式化
     *
     * @return java.lang.Object
     * @Param [cell]
     * @Author ywx
     * @Date 2020/6/3 16:41
     **/
    public static String getCellValue(Cell cell) {
        String value = null;
        if (cell == null) return value;
        DecimalFormat df = new DecimalFormat("0.##");  //格式化number String字符
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");  //日期格式化
        switch (cell.getCellTypeEnum()) {
            case STRING:
                value = cell.getRichStringCellValue().getString();
                break;
            case NUMERIC:
                String cellStyle = cell.getCellStyle().getDataFormatString();
                if ("General".equals(cellStyle)) {
                    Double d = cell.getNumericCellValue();
                    if (d.toString().contains("E")) {
                        cell.setCellType(CellType.STRING);
                        value = cell.getStringCellValue();
                    } else {
                        value = df.format(d);
                    }
                } else if ("m/d/yy".equals(cellStyle)) {
                    value = sdf.format(cell.getDateCellValue());
                } else {
                    value = df.format(cell.getNumericCellValue());
                }
                break;
            case BOOLEAN:
                boolean rtn = cell.getBooleanCellValue();
                if (rtn) {
                    value = "1";//真
                } else {
                    value = "0";//假
                }
                break;
            case BLANK:
                value = "";
                break;
            case FORMULA://读取excel公式的值
                try {
                    value = String.valueOf(cell.getNumericCellValue());
                } catch (IllegalStateException e) {
                    value = String.valueOf(cell.getRichStringCellValue());
                }
                break;
            default:
                break;
        }
        return N_Utils.strTrim(value);
    }

    /**
     * 检验Excel内容是否为空
     *
     * @return void
     * @Param [file]
     * @Author ywx
     * @Date 2020/6/3 16:36
     **/
    public static void isExcelEmpty(MultipartFile file) throws Exception {
        if (null == file || file.isEmpty()) {
            throw new Exception("文件不存在！");
        }
        InputStream in = file.getInputStream();
        String fileName = file.getOriginalFilename();
        Workbook work = getWorkbook(in, fileName);
        if (null == work) {
            throw new Exception("Excel内容为空！");
        }
        Integer sheet_size = work.getNumberOfSheets();
        if (sheet_size == 0) {
            throw new Exception("Excel内容为空！");
        }
    }
}
