package com.rongwei.bscommon.sys.service.impl;

import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.rongwei.bscommon.sys.dao.QuShiftDao;
import com.rongwei.bscommon.sys.dao.QuShiftDetailDao;
import com.rongwei.bscommon.sys.dao.QuestionCommonSqlDao;
import com.rongwei.bscommon.sys.service.ImportService;
import com.rongwei.bsentity.domin.QuShiftDetailDo;
import com.rongwei.bsentity.domin.QuShiftDo;
import com.rongwei.bsentity.vo.ShiftVo;
import com.rongwei.rwadmincommon.system.domain.SysOrganizationDo;
import com.rongwei.rwadmincommon.system.domain.SysUserDo;
import com.rongwei.rwcommon.base.R;
import com.rongwei.rwcommon.utils.SecurityUtil;
import com.rongwei.rwcommonentity.commonservers.domain.SysFileItemDo;
import org.apache.commons.lang.StringUtils;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.File;
import java.text.DecimalFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * ImportServiceImpl class
 *
 * @author XH
 * @date 2023/04/04
 */
@Service
public class ImportShiftServiceImpl implements ImportService {
    private final Logger log = LoggerFactory.getLogger(this.getClass().getName());
    @Autowired
    private QuestionCommonSqlDao questionCommonSqlDao;
    @Autowired
    private QuShiftServiceImpl quShiftService;
    @Autowired
    private QuShiftDetailServiceImpl quShiftDetailService;
    @Autowired
    private QuShiftDao quShiftDao;
    @Autowired
    private QuShiftDetailDao quShiftDetailDao;


    /**
     * 排班信息导入
     *
     * @param fileId excelId
     */
    @Override
    public R importByFileId(String fileId) {
        File file = getFile(fileId);
        ExcelReader reader = ExcelUtil.getReader(file);
        List<Sheet> sheets = reader.getSheets();
        // 获取第一个sheet 页
        Sheet firstSheet = sheets.get(0);
        // 获取后一行
        int lastRowNum = firstSheet.getLastRowNum();
        if (lastRowNum == 0) {
            return R.error("没有维护排班信息");
        }
        // 第一行获取对应的年和月份
        Row yearAndMonthRow = firstSheet.getRow(0);
        DecimalFormat format = new DecimalFormat("0");
        Integer year = null;
        Integer month = null;
        try {
            // 年
            year = Integer.parseInt(getCellValue(yearAndMonthRow.getCell(1), "年", format));
            //
            month = Integer.parseInt(getCellValue(yearAndMonthRow.getCell(3), "月", format));
        } catch (Exception e) {
            log.error("模板年：{}月: {}格式异常", year, month);
            throw new RuntimeException("模板年月格式异常");
        }
        List<ShiftVo> excelData;
        try {
            excelData = getExcelData(year, month, lastRowNum, firstSheet, format);
        } catch (RuntimeException e) {
            throw e;
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("模板异常!请联系系统管理员");
        }
        if (excelData.isEmpty()) {
            log.debug("excel中暂无数据");
            return R.error("没有维护排班信息");
        }
        List<QuShiftDo> quShiftDos = new ArrayList<>();
        List<QuShiftDetailDo> quShiftDetailDos = new ArrayList<>();
        // vo转实体
        voConvertDo(excelData, quShiftDos, quShiftDetailDos, year, month);
        // 数据存表
        dataSave(quShiftDos, quShiftDetailDos);
        return R.ok();
    }

    /**
     * 存表
     *
     * @param quShiftDos
     * @param quShiftDetailDos
     */
    private void dataSave(List<QuShiftDo> quShiftDos,
                          List<QuShiftDetailDo> quShiftDetailDos) {
        // 先根据记录查询当前是否存在时间 存在直接删除然后新增
        Integer yearnum = quShiftDos.get(0).getYearnum();
        Integer monthnum = quShiftDos.get(0).getMonthnum();
        // 获取当前年月的排班记录
        List<QuShiftDo> list = quShiftService.list(new LambdaQueryWrapper<QuShiftDo>().eq(QuShiftDo::getYearnum, yearnum).eq(QuShiftDo::getMonthnum, monthnum));
        List<String> workshopAndSectionList = quShiftDos.stream().map(info -> info.getWorkshop() + ";" + info.getSection()).collect(Collectors.toList());
        // 找到 车间和工段已存在的数据
        List<String> deletedIds = list.stream().filter(info -> workshopAndSectionList.contains(info.getWorkshop() + ";" + info.getSection())).map(QuShiftDo::getId).collect(Collectors.toList());
        if (!deletedIds.isEmpty()) {
            quShiftDao.deleteByIds(deletedIds);
            quShiftDetailDao.deleteByShiftId(deletedIds);
        }
        quShiftService.saveBatch(quShiftDos);
        quShiftDetailService.saveBatch(quShiftDetailDos);
    }

    /**
     * vo 转实体
     *
     * @param shiftVoList
     */
    private void voConvertDo(List<ShiftVo> shiftVoList, List<QuShiftDo> quShiftDos, List<QuShiftDetailDo> quShiftDetailDos, int year, int month) {
        // 对数据按照 车间工段进行分组
        Map<String, List<ShiftVo>> workShopAndSectionMap = shiftVoList.stream().collect(Collectors.groupingBy(info -> info.getWorkshop() + ";" + info.getSection()));
        List<SysOrganizationDo> allOrg = questionCommonSqlDao.getAllOrg();
        List<SysUserDo> alluser = questionCommonSqlDao.getAlluser();
        workShopAndSectionMap.forEach((workShopAndSection, value) -> {
            QuShiftDo quShiftDo = new QuShiftDo();
            quShiftDo.setMonthnum(month);
            quShiftDo.setYearnum(year);
            quShiftDo.setId(SecurityUtil.getUUID());
            quShiftDo.setCreatedate(new Date());
            quShiftDo.setModifydate(new Date());
            quShiftDo.setCreateusername("import");
            quShiftDo.setModifyusername("import");
            quShiftDo.setWorkshop(getOrgIdByOrgName(allOrg, workShopAndSection.split(";")[0]));
            quShiftDo.setSection(getOrgIdByOrgName(allOrg, workShopAndSection.split(";")[1]));
            quShiftDos.add(quShiftDo);
            // 对数据按照 日期排序并分组
            LinkedHashMap<Integer, List<ShiftVo>> dayInfoMap = value.stream()
                    .sorted(Comparator.comparing(ShiftVo::getDay))
                    .collect(Collectors.groupingBy(ShiftVo::getDay, LinkedHashMap::new, Collectors.toList()));
            dayInfoMap.forEach((day, shiftList) -> {
                QuShiftDetailDo quShiftDetailDo = new QuShiftDetailDo();
                quShiftDetailDo.setId(SecurityUtil.getUUID());
                quShiftDetailDo.setShiftid(quShiftDo.getId());
                quShiftDetailDo.setCreatedate(new Date());
                quShiftDetailDo.setModifydate(new Date());
                quShiftDetailDo.setCreateusername("import");
                quShiftDetailDo.setModifyusername("import");
                quShiftDetailDo.setDaynum(day);
                quShiftDetailDo.setForeshift(getUserByShiftType(shiftList, "早,白", alluser));
                quShiftDetailDo.setMiddleshift(getUserByShiftType(shiftList, "中", alluser));
                quShiftDetailDo.setNightshift(getUserByShiftType(shiftList, "夜,晚", alluser));
                quShiftDetailDo.setRestshift(getUserByShiftType(shiftList, "休", alluser));
                quShiftDetailDos.add(quShiftDetailDo);
            });
        });
    }

    /**
     * 根据班组获取员工工号
     *
     * @param shiftVoList
     * @param shiftType
     * @return
     */
    private String getUserByShiftType(List<ShiftVo> shiftVoList, String shiftType, List<SysUserDo> alluser) {
        ShiftVo shiftVo = shiftVoList.stream().filter(info ->StringUtils.isNotBlank(info.getShift())&& shiftType.contains(info.getShift())).findFirst().orElse(null);
        if (shiftVo == null) {
            return "";
        }
        Map<String, String> accountAndIdMap = alluser.stream().collect(Collectors.toMap(SysUserDo::getAccount, SysUserDo::getId));
        return accountAndIdMap.getOrDefault(shiftVo.getJobNum(), "");
    }

    /**
     * 获取组织机构ID
     *
     * @param sysOrganizationDos
     * @param orgName
     * @return
     */
    private String getOrgIdByOrgName(List<SysOrganizationDo> sysOrganizationDos, String orgName) {
        if (StringUtils.isBlank(orgName)) {
            log.error("工段或车间为空");
            throw new RuntimeException("未维护工段或车间");
        }
        SysOrganizationDo sysOrganizationDo = sysOrganizationDos.stream().filter(info -> orgName.equals(info.getFullname())).findFirst().orElse(null);
        if (sysOrganizationDo == null) {
            log.error("无法通过组织机构名称：{},获取到数据", orgName);
            throw new RuntimeException("工段或车间名称错误");
        }
        return sysOrganizationDo.getId();
    }

    /**
     * 获取模板文件
     *
     * @param fileId
     * @return
     */
    private File getFile(String fileId) {
        if (StringUtils.isBlank(fileId)) {
            log.error("附件ID 为空");
        }
        SysFileItemDo fileItemDo = questionCommonSqlDao.getFileItemByID(fileId);
        if (fileItemDo == null) {
            log.error("无法根据文件ID:{},获取到文件信息", fileId);
            throw new RuntimeException("文件解析有误!请联系管理员");
        }

        String realPath = fileItemDo.getFullpath();
        if (StringUtils.isBlank(realPath)) {
            log.error("根据文件ID:{},无法获取到文件路径", fileId);
            throw new RuntimeException("文件解析有误!请联系管理员");
        }
        File file = new File(realPath);
        if (!file.exists()) {
            log.error("根据文件地址:{},无法获取文件", fileId);
            throw new RuntimeException("文件解析有误!请联系管理员");
        }
        return file;
    }

    /**
     * 从EXCEL 中获取数据
     *
     * @return
     */
    public List<ShiftVo> getExcelData(Integer year, Integer month,
                                      int lastRowNum, Sheet firstSheet,
                                      DecimalFormat format) {
        Calendar instance = Calendar.getInstance();
        instance.set(year, month, 1);
        instance.add(Calendar.DATE, -1);
        // 获取当前年月的最大天数
        int nowDateMaxDays = instance.get(Calendar.DATE);
        Row dataRow;
        // 车间
        Cell workshopCell;
        // 工段
        Cell sectionCell;
        // 工号
        Cell jobNumCell;
        // 姓名
        Cell nameCell;
        // 班组
        Cell shiftCell;
        // 保存Excel数据 key 为 车间;工段;工号;姓名
        List<ShiftVo> shiftVoList = new ArrayList<>();
        ShiftVo shiftVo;

        for (int i = 2; i <= lastRowNum; i++) {
            // 获取到数据行
            dataRow = firstSheet.getRow(i);
            workshopCell = dataRow.getCell(0);
            sectionCell = dataRow.getCell(1);
            jobNumCell = dataRow.getCell(2);
            nameCell = dataRow.getCell(3);
            for (int j = 1; j <= nowDateMaxDays; j++) {
                shiftVo = new ShiftVo();
                shiftCell = dataRow.getCell(3 + j);
                shiftVo.setWorkshop(getCellValue(workshopCell, "车间", format));
                shiftVo.setSection(getCellValue(sectionCell, "工段", format));
                shiftVo.setJobNum(getCellValue(jobNumCell, "工号", format));
                shiftVo.setName(getCellValue(nameCell, "姓名", format));
                if (shiftCell != null && StringUtils.isNotBlank(shiftCell.getStringCellValue())) {
                    shiftVo.setShift(shiftCell.getStringCellValue());
                }
                shiftVo.setDay(j);
                shiftVoList.add(shiftVo);
            }
        }
        return shiftVoList;
    }

    /**
     * 获取单元格数据
     *
     * @return
     */
    private String getCellValue(Cell currentCell, String cellName, DecimalFormat format) {
        if (currentCell == null || CellType._NONE.equals(currentCell.getCellType()) || CellType.ERROR.equals(currentCell.getCellType())) {
            throw new RuntimeException(String.format("存在未填写%s的单元格请检查模板", cellName));
        }
        String cellValue = "";
        if (CellType.STRING.equals(currentCell.getCellType())) {
            cellValue = currentCell.getStringCellValue();
        }
        if (CellType.NUMERIC.equals(currentCell.getCellType()) || CellType.FORMULA.equals(currentCell.getCellType())) {
            cellValue = format.format(currentCell.getNumericCellValue());
        }
        if (StringUtils.isBlank(cellValue)) {
            throw new RuntimeException(String.format("存在未填写%s的单元格请检查模板", cellName));
        }
        return cellValue;
    }

}
