package com.xhkjedu.sapi.utils;

import com.xhkjedu.sapi.model.assess.TAssessUser;
import com.xhkjedu.sapi.model.system.TSchool;
import com.xhkjedu.sapi.model.system.TUser;
import com.xhkjedu.sapi.service.assess.AssessUserService;
import com.xhkjedu.sapi.vo.subjectbook.SubjectVo;
import com.xhkjedu.utils.MD5;
import com.xhkjedu.utils.N_Utils;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.BeanUtils;
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.*;

/**
 * @author ywx
 * @classname PoiUtils
 * @description
 * @date 2020/6/3 16:33
 **/
@Component
@Slf4j
public class PoiUtils {
    //2003- 版本的excel
    private final static String excel2003L = ".xls";
    //2007+ 版本的excel
    private final static String excel2007U = ".xlsx";

    /**
     * 导入班级学生
     *
     * @return java.lang.String
     * @Param [file]
     * @Author ywx
     * @Date 2020/6/3 16:43
     **/
    public static Map<String, Object> readExcelUser(MultipartFile file, Integer usertype) throws Exception {
        Map<String, Object> resultMap = new HashMap<>();
        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）

            // 导入用户信息
            List<TUser> users = new ArrayList<>();
            // excel已存在学生信息
//            List<TUser> excelExisted = new ArrayList<>();
            Map<String,String> nameMap = new HashMap<>();

            /*
             * 遍历当前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;
                }
                TUser user = new TUser();// 每一行一个学生信息
                user.setUsertype(usertype);
                int firstCellNum = row.getFirstCellNum();// 每一行的第一列，（firstCellNum=0）
                if (firstCellNum == 1) throw new Exception("第" + (x + 1) + "行姓名不能为空");
                int lastCellNum = row.getLastCellNum();// 每一行的最后一列，获取列数，比最后一列列标大1
                //遍历所有的列
                for (int y = firstCellNum; y < lastCellNum; y++) {
                    Cell cell = row.getCell(y);
                    if (y == 0){   // 姓名
                        setUserName(cell, x, user);
                    } else if(y == 1){// 登录名
                        if (isEmptyCell(cell) ){
                            throw new Exception("第"+(x+1)+"行登录账号不能为空");
                        } else{
                            String loginname = getCellValue(cell);
                            user.setLoginname(loginname);//登录名默认为学号
                            if (2 == usertype) {//导入学生登录账号默认为学号
                                user.setStudentno(loginname);
                            }
                            MD5 md5 = new MD5();
                            user.setLoginpwd(md5.getMD5ofStr(md5.getMD5ofStr(md5.getMD5ofStr("123456"))));
                        }
                    } else if(y == 2){//性别
                        if (isEmptyCell(cell) ){
                            user.setUsersex(0);
                        } else {
                            String usersex = getCellValue(cell);
                            if (usersex.equals("女")){
                                user.setUsersex(2);
                            } else {
                                user.setUsersex(1);
                            }
                        }
                    } else if(y == 3){//手机号
                        setUserPhone(cell, x, user);
                    } else if(y == 4){//出生日期
                        if (!isEmptyCell(cell) ){
                            String birthDay = getCellValue(cell);
                            user.setUserbirthday(N_Utils.getDataToTimestamp(birthDay,"yyyy-MM-dd"));
                        }
                    } else if(y == 5){//身份证号
                        if (isEmptyCell(cell) ){
                            user.setCardid("");
                        } else {
                            user.setCardid(getCellValue(cell));
                        }
                    }
                }

                String loginname = user.getLoginname();
                if (N_Utils.isNotEmpty(nameMap.get(loginname))) {
//                    excelExisted.add(user);
                } else {
                    nameMap.put(loginname,loginname);
                    users.add(user);
                }
            }

            resultMap.put("code" , 0);
            resultMap.put("users" , users);
//            resultMap.put("excelExisted" , excelExisted);
        }catch (Exception e){
            resultMap.put("code" , 1);
            resultMap.put("msg" , e.getMessage());
            throw new Exception(e.getMessage());
        }
        return resultMap;
    }

    private static void setUserName(Cell cell, int x, TUser user) throws Exception {
        if (isEmptyCell(cell)) {
            throw new Exception("第" + (x + 1) + "行姓名不能为空");
        } else {
            user.setUsername(getCellValue(cell));
        }
    }

    private static void setUserPhone(Cell cell, int x, TUser user) throws Exception {
        if (isEmptyCell(cell)) {
            user.setUserphone("");
        } else {
            String phone = getCellValue(cell);
            if (!N_Utils.isPhone(phone)) {
                throw new Exception("第" + (x + 1) + "行手机号码格式不正确");
            }
            user.setUserphone(phone);
        }
    }

    /**
     * 根据文件后缀，自适应上传文件的版本
     * @Param [inStr, fileName]
     * @Author ywx
     * @Date 2020/6/3 16:42
     * @return org.apache.poi.ss.usermodel.Workbook
     **/
    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;
    }

    /**
     * 判断单元格是否是空值
     * @Param [cell]
     * @Author ywx
     * @Date 2020/6/3 16:37
     * @return java.lang.Boolean
     **/
    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;
        }
    }

    /**
     * 对表格中数值进行格式化
     * @Param [cell]
     * @Author ywx
     * @Date 2020/6/3 16:41
     * @return java.lang.Object
     **/
    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");  //日期格式化
        DecimalFormat df2 = new DecimalFormat("0");  //格式化数字

        switch (cell.getCellType()) {
            case Cell.CELL_TYPE_STRING:
                value = cell.getRichStringCellValue().getString();
                break;
            case Cell.CELL_TYPE_NUMERIC:
                String cellStyle = cell.getCellStyle().getDataFormatString();
                if("General".equals(cellStyle)){
                    value = df.format(cell.getNumericCellValue());
                }else if("m/d/yy".equals(cellStyle)){
                    value = sdf.format(cell.getDateCellValue());
                }else{
                    value = df2.format(cell.getNumericCellValue());
                }
                break;
            case Cell.CELL_TYPE_BOOLEAN:
                boolean rtn = cell.getBooleanCellValue();
                if (rtn){
                    value = "1";//真
                } else {
                    value = "0";//假
                }
                break;
            case Cell.CELL_TYPE_BLANK:
                value = "";
                break;
            case HSSFCell.CELL_TYPE_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内容是否为空
     * @Param [file]
     * @Author ywx
     * @Date 2020/6/3 16:36
     * @return void
     **/
    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内容为空！");
        }
    }

    /**
     * 评价导入
     *
     * @return java.util.Map<java.lang.String, java.lang.Object>
     * @Param [file]
     * @Author ywx
     * @Date 2021/12/6 15:49
     **/
    public static Map<String, Object> readAssess(MultipartFile file, Integer schoolid, Integer templateid, AssessUserService assessService) {
        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）

            // 导入用户信息
            List<TAssessUser> users = new ArrayList<>();
            Map<String, Integer> grades = N_Utils.listGrade();
            TSchool school = assessService.getSchoolById(schoolid);
            List<SubjectVo> subject = assessService.listSubject(schoolid, school.getSchoollevel());
            Map<String, String> subjects = new HashMap();
            subject.forEach(s -> {
                subjects.put(s.getSubjectname(), s.getSubjectid());
            });

            List<Map> quotas = assessService.listChildQuotaByTemplateId(templateid);//获取模板下的子指标

            /*
             * 遍历当前sheet中的所有行
             * 排除前两行 第一行（标题）第二行（字段类型） 不纳入遍历
             */
            for (int x = firstRowNum + 2; x <= rows; x++) {
                // 获取行
                row = sheet.getRow(x);
                if (row == null) {//若此行为空，则跳出循环继续下一行
                    continue;
                } else if (isEmptyCell(row.getCell(0)) && isEmptyCell(row.getCell(1))) {
                    continue;
                }
                int firstCellNum = row.getFirstCellNum();// 每一行的第一列，（firstCellNum=0）
                if (firstCellNum == 1) throw new Exception("第" + (x + 1) + "行姓名不能为空");
                int lastCellNum = row.getLastCellNum();// 每一行的最后一列，获取列数，比最后一列列标大1
                Integer gradeid = null;
                Integer classid = null;
                String subjectid = null;
                Integer snum = null;
                List<String> mrows = new ArrayList<>();
                TAssessUser au = new TAssessUser();
                au.setSchoolid(schoolid);
                //遍历所有的列
                for (int y = firstCellNum; y < lastCellNum; y++) {
                    Cell cell = row.getCell(y);
                    if (y == 1) {// 日期
                        String date = getCellValue(cell);
                        if (N_Utils.isEmpty(date)) {
                            break;
                        } else {
                            date = date.replaceAll("-", "").replaceAll("/", "");
                            if (date.length() != 8) {
                                mrows.add("日期格式不对");
                            } else {
                                au.setAutime(N_Utils.getDataToTimestamp(date, "yyyyMMdd"));
                            }
                        }
                    } else if (y == 3) {//节次
                        String _snum = getCellValue(cell);
                        snum = N_Utils.str2Int(_snum);
                        au.setSnum(snum);
                    } else if (y == 4) {//学科
                        String subjectname = getCellValue(cell);
                        if (N_Utils.isEmpty(subjectname)) {
                            mrows.add("科目不能为空");
                        }
                        subjectid = subjects.get(subjectname);
                        if (N_Utils.isEmpty(subjectid)) {
                            mrows.add("科目不存在");
                        } else {
                            au.setSubjectid(subjectid);
                        }
                    } else if (y == 5) {//年级
                        String gradename = getCellValue(cell);
                        if (N_Utils.isEmpty(gradename)) {
                            mrows.add("年级不能为空");
                        }
                        gradeid = grades.get(gradename);
                        au.setGradeid(gradeid);
                    } else if (y == 6) {//班级
                        String classname = getCellValue(cell);
                        if (N_Utils.isEmpty(classname)) {
                            mrows.add("班级不能为空");
                        }
                        classid = assessService.getClassIdByName(classname, schoolid, gradeid, school.getYear());
                        if (N_Utils.isEmptyInteger(classid)) {
                            mrows.add("班级不存在");
                        } else {
                            au.setClassid(classid);
                        }
                    } else if (y == 7) {//学生表扬
                        setAssessUser(assessService, row, mrows, au, y, cell, 1, 2, users, quotas);
                        y = 9;
                    } else if (y == 10) {//学生批评
                        setAssessUser(assessService, row, mrows, au, y, cell, 2, 2, users, quotas);
                        y = 12;
                    } else if (y == 13) {//教师表扬
                        setAssessUser(assessService, row, mrows, au, y, cell, 1, 1, users, quotas);
                        y = 14;
                    } else if (y == 15) {//教师批评
                        setAssessUser(assessService, row, mrows, au, y, cell, 2, 1, users, quotas);
                        y = 16;
                        if (N_Utils.isListNotEmpty(mrows)) {
                            errMsg.put(x + 1, mrows);
                        }
                    }
                }
            }

            resultMap.put("code", 0);
            resultMap.put("users", users);
        } catch (Exception e) {
            resultMap.put("code", 1);
            resultMap.put("msg", e.getMessage());
            log.error("读取评价用户出错", e.getMessage());
        }
        resultMap.put("errMsg", errMsg);
        return resultMap;
    }

    //设置评价用户信息
    private static void setAssessUser(AssessUserService assessService, Row row, List<String> mrows
            , TAssessUser au, int y, Cell cell, Integer autype, Integer usertype, List<TAssessUser> users, List<Map> quotas) {
        String username = getCellValue(cell);
        if (N_Utils.isNotEmpty(username)) {
            Map idNum;
            String type;
            if (usertype == 2) {
                //根据班级id用户名获取学生id和数量
                idNum = assessService.getUserIdByName(au.getSchoolid(), au.getClassid(), username);
                type = "本班下学生";
            } else {
                //根据班级id用户名获取教师id和数量
                idNum = assessService.getUserIdByName2(au.getSchoolid(), au.getClassid(), username);
                type = "本班下教师";
            }
            Integer num = N_Utils.str2Int(idNum.get("num").toString());
            if (num == 0) {
                mrows.add(type + "【" + username + "】不存在");
            } else if (num == 1) {
                Integer userid = (Integer) idNum.get("userid");
                TAssessUser user = new TAssessUser();
                BeanUtils.copyProperties(au, user);
                user.setUsertype(usertype);
                user.setAutype(autype);
                user.setUserid(userid);
                user.setAunum(1);
                Integer index;
                if (usertype == 2) {//学生
                    String stutype = getCellValue(row.getCell(y + 1));
                    user.setStutype(stutype);
                    index = y + 2;
                } else {//教师
                    index = y + 1;
                }
                String quotaname = getCellValue(row.getCell(index));
                Map quota = quotas.stream().filter(m -> m.get("quotaname").equals(quotaname)
                        || m.get("quotacode").equals(quotaname)).findFirst().orElse(null);
                if (quota == null) {
                    mrows.add("【" + quotaname + "】评价标准不存在");
                } else {
                    user.setQuotaid((Integer) quota.get("quotaid"));
                }
                users.add(user);
            } else if (num > 1) {
                mrows.add(type + "【" + username + "】存在多个");
            }
        }
    }
}
