package com.engine.jucailinkq.attendance.component.ImportAndExport.service.impl;

import cn.hutool.core.util.StrUtil;
import com.cloudstore.eccom.pc.table.WeaTableColumn;
import com.engine.jucailinkq.attendance.component.ImportAndExport.service.ExcelExportImportService;
import com.engine.jucailinkq.attendance.component.ImportAndExport.service.param.ImportParam;
import com.engine.jucailinkq.attendance.component.calendarscheduling.service.WorkRulesService;
import com.engine.jucailinkq.attendance.component.calendarscheduling.service.impl.WorkRulesServiceImpl;
import com.engine.jucailinkq.attendance.enums.ApplicableOrganizationEnum;
import com.engine.jucailinkq.attendance.enums.SchedulingApproachEnum;
import com.engine.jucailinkq.common.exception.AttendanceRunTimeException;
import com.engine.common.util.*;
import com.engine.jucailinkq.common.util.CommonUtil;
import com.engine.jucailinkq.common.util.DateUtil;
import com.engine.jucailinkq.common.util.DbTools;
import com.engine.jucailinkq.common.util.Utils;
import com.engine.jucailinkq.common.util.excel.ExcelParseHelper;
import com.engine.jucailinkq.common.util.excel.ExcelSupport;
import com.engine.jucailinkq.common.util.excel.ExcelUtil;
import com.engine.core.impl.Service;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.util.IOUtils;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import weaver.file.ImageFileManager;
import weaver.general.Util;
import weaver.hrm.User;

import java.io.InputStream;
import java.util.*;
import java.util.stream.Collectors;

import static com.engine.jucailinkq.common.util.excel.ExcelSupport.EXCEL_TYPE_XLSX;

/**
 * @Author: sy
 * @Description:
 * @Date: 2024/6/5
 **/
@Slf4j
public class ExcelExportImportServiceImpl extends Service implements ExcelExportImportService {

    private WorkRulesService getWorkRulesService(User user) {
        return ServiceUtil.getService(WorkRulesServiceImpl.class,user);
    }

    @Override
    public XSSFWorkbook exportSchedule(Map<String, Object> paramMap) {
      String total = Util.null2String(paramMap.get("total"));
        if ("".equals(total) || "0".equals(total)) {
            paramMap.put("pageSize", "9999");
        } else {
            paramMap.put("pageSize", total);
        }
        paramMap.put("pageindex", "1");
        log.debug("查询条件:{}",paramMap);
        Map<String, Object> scheduleResult = getWorkRulesService(user).getDepartSchedule(paramMap);
        List<WeaTableColumn> columns = buildScheduleColumns((List<Map<String, Object>>) scheduleResult.get("columns"));
        List<Map<String, Object>> records = buildScheduleRecords((List<Map<String, Object>>) scheduleResult.get("datas"));

        List<List<Object>> excelSheetData = new ArrayList<>();
        //工作簿名称
        String sheetName = "日历排班";
        excelSheetData.add(Arrays.asList(columns.stream().map(WeaTableColumn::getText).toArray()));

        //工作簿数据
        List<List<Object>> rows = new LinkedList<>();
        for (Map<String, Object> recordData : records) {
            List<Object> row = new LinkedList<>();
            for (WeaTableColumn column : columns) {
                row.add(recordData.get(column.getColumn()));
            }
            rows.add(row);
        }

        excelSheetData.addAll(rows);
        String dateTime = Util.null2String(paramMap.get("dateTime"));
        return ExcelUtil.genWorkbookV2(excelSheetData, sheetName, dateTime, columns.size());
    }

    private List<Map<String, Object>> buildScheduleRecords(List<Map<String, Object>> dataInfo) {
        List<Map<String, Object>> result = new ArrayList<>();
        if (dataInfo != null && dataInfo.size() > 0) {
            Map<String, Object> dayItem;
            Map<String, Object> record;
            for (Map<String, Object> dataItem : dataInfo) {
                record = new HashMap<>();
                record.put("workcode", Util.null2String(dataItem.get("workcode")));
                record.put("lastname", Util.null2String(dataItem.get("lastname")));
                record.put("subcompany", Util.formatMultiLang(Util.null2String(dataItem.get("subcompany")), "" + user.getLanguage()));
                record.put("department", Util.formatMultiLang(Util.null2String(dataItem.get("department")), "" + user.getLanguage()));
                for (Map.Entry<String, Object> entry : dataItem.entrySet()) {
                    if (DateUtil.dateIsValid(entry.getKey())) {
                        dayItem = (Map<String, Object>) entry.getValue();
                        record.put(entry.getKey(), Util.null2String(dayItem.get("title")));
                    }
                }
                result.add(record);
            }
        }
        return result;
    }

    private List<WeaTableColumn> buildScheduleColumns(List<Map<String,Object>> columnInfo) {
        List<WeaTableColumn> list = new ArrayList<>();
        if (columnInfo != null && columnInfo.size() > 0) {
            for (Map<String, Object> columnItem : columnInfo) {
                list.add(new WeaTableColumn("150px", Util.null2String(columnItem.get("context")), Util.null2String(columnItem.get("dataIndex"))));
            }
        }
        return list;
    }

    @Override
    public Map<String, Object> importSchedule(ImportParam param) {

        if (StringUtils.isBlank(param.getImageId())) {
            throw new AttendanceRunTimeException("导入文件id为空！");
        }
        int successCount = 0;
        int errorCount = 0;
        //查询formmodeid
        Map<String,String> formModeIdMap = Utils.getFormmodeIdMap();
        String formModeId = formModeIdMap.get("uf_pbjg");
        // 获取所有人员信息
        List<Map<String, Object>> employeeInfoList = getAllEmpInfo();
        //获取班次名称对于班次信息的映射
        Map<String,Object> shiftMapWithMc = getShiftInfoToMc();
        // 待入库数据
        List<Map<String, Object>> toImportScheduleInfos = new ArrayList<>();
        // 待处理数据
        InputStream fileInputStream = null;
        // 待处理数据关联的人员ids
        List<String> empIds = new ArrayList<>();
        try {
            fileInputStream = ImageFileManager.getInputStreamById(Integer.parseInt(param.getImageId()));
            if (fileInputStream == null) {
                throw new AttendanceRunTimeException("excel文件解析失败！");
            }
            Sheet sheet = ExcelSupport.parseFile(fileInputStream, 0, EXCEL_TYPE_XLSX);
            //标题
            List<String> titles = ExcelSupport.getSheetHeader(sheet, 0);
            String title = titles.get(0);
            log.debug("处理前年月信息:{}",title);
            //年月格式的转换处理
            if (StrUtil.isNotBlank(title) && title.length() > 7) {
                title = title.substring(0, 7);
                log.debug("处理后年月信息:{}",title);
            }
            if (StrUtil.isNotBlank(title) && !DateUtil.checkYearMonth(title.replace("/",  "-"))) {
                throw new AttendanceRunTimeException("excel首行'年月'时间格式错误,正确格式为yyyy-mm或者yyyy-mm-dd或者yyyy/mm或者yyyy/mm/dd");
            }
            int monthDays = DateUtil.getDays(title, Calendar.DAY_OF_MONTH);
            // 表头
            List<String> headers = ExcelSupport.getSheetHeader(sheet, 1);
            log.debug("headers数据：{}", headers);
            // 错误sheet数据
            List<Map<String, Object>> errorData = new LinkedList<>();
            // 错误提示
            List<Map<String, String>> excelComments = new LinkedList<>();
            // 处理数值
            List<Map<String, Object>> data = ExcelParseHelper.parse2Map(sheet, 2, 1);
            log.debug("excel导入数据：[{}]", data);
            //单行记录
            Map<String, Object> map;
            for (int i = 0; i < data.size(); i++) {
                map = data.get(i);
                boolean isError = false;
                Map<String, String> singleCheck = new HashMap<>();
                for (int j = 0; j < headers.size(); j++) {
                    //组装单条数据基础数据
                    String key = headers.get(j);
                    if (key == null) {
                        continue;
                    }
                    singleCheck.put(key, Optional.ofNullable(map.get(key)).orElse("").toString());
                }
                log.debug(i + 3 + "-singleCheck：{}", singleCheck);
                isError = singleScheduleLineCheck(singleCheck, title, monthDays, toImportScheduleInfos, employeeInfoList, shiftMapWithMc, excelComments, i + 3, formModeId, empIds);
                if (isError) {
                    errorCount += 1;
                    // 添加错误数据
                    errorData.add(map);
                } else {
                    successCount += 1;
                }
            }
            // 数据入库处理
            handleScheduleImportData(toImportScheduleInfos, empIds, title, monthDays);

            Map<String, Object> apidatas = new HashMap<String, Object>();
            apidatas.put("successCount", successCount);
            apidatas.put("errorCount", errorCount);
            apidatas.put("errorData", excelComments);
            return apidatas;
        } finally {
            IOUtils.closeQuietly(fileInputStream);
        }

    }

    private List<Map<String, Object>> getAllEmpInfo() {
        String sql = "select a.id, a.lastname, a.workcode, d.departmentname, s.subcompanyname " +
                "from hrmresource a left join hrmdepartment d on d.id = a.departmentid " +
                "left join hrmsubcompany s on s.id =  a.subcompanyid1 ";
        List<Map<String, Object>> empInfo = DbTools.getSqlToList(sql);
        return empInfo;
    }

    private Map<String, Object> getShiftInfoToMc() {
        String sql = "select id, mc, sfxx from uf_jcl_kq_bcxx ";
        List<Map<String, Object>> shiftInfo = DbTools.getSqlToList(sql);
        Map<String,Object> shiftMapWithMc = shiftInfo.stream().collect(Collectors.toMap(e->e.get("mc").toString(), e->e));
        return shiftMapWithMc;
    }

    public boolean singleScheduleLineCheck(Map<String, String> singleCheck, String yearMonth, int monthDays,
                                      List<Map<String, Object>> toImportScheduleInfos, List<Map<String, Object>> employeeByIds,
                                           Map<String,Object> shiftMapWithMc, List<Map<String, String>> excelComments, int index, String formModeId, List<String> empIds) {
        boolean isError = false;
        String workCode = Util.null2String(singleCheck.get("编号"));
        String lastName = Util.null2String(singleCheck.get("姓名"));
        String subCompany = Util.null2String(singleCheck.get("分部"));
        String department = Util.null2String(singleCheck.get("部门"));
        String rowIndex = "第" + index + "行";
        //校验该行数据中员工信息是否唯一存在
        List<Map<String, Object>> targetEmpInfo = matchImportEmp(employeeByIds, lastName, subCompany, department, workCode);
        if (CollectionUtils.isEmpty(targetEmpInfo)) {
            Map<String, String> errorMessageMap = new HashMap<>();
            errorMessageMap.put("message", rowIndex + "员工信息不存在！");
            excelComments.add(errorMessageMap);
            isError = true;
            return isError;
        } else if (targetEmpInfo.size() > 1) {
            Map<String, String> errorMessageMap = new HashMap<>();
            errorMessageMap.put("message", rowIndex + "员工信息存在多个匹配的员工！");
            excelComments.add(errorMessageMap);
            isError = true;
            return isError;
        }
        String employeeId = Util.null2String(targetEmpInfo.get(0).get("id"));
        if (empIds.size() > 0 && empIds.contains(employeeId)) {
            Map<String, String> errorMessageMap = new HashMap<>();
            errorMessageMap.put("message", rowIndex + "表格中同一员工不可存在多组排班数据！");
            excelComments.add(errorMessageMap);
            isError = true;
            return isError;
        }
        //获取目标人员目标月日期类型对日期的映射
        List<Map<String,Object>> rqlxInfo = CommonUtil.getYearCalendarList(employeeId, yearMonth.substring(0, 4));
        Map<String, String> rqlxInfoWithRq = rqlxInfo.stream().filter(f -> f.get("rq").toString().contains(yearMonth)).collect(Collectors.toMap(e->e.get("rq").toString(), e->e.get("rqlx").toString()));
        //暂存本次调用中的导入数据
        List<Map<String, Object>> singleToImportScheduleInfos  = new ArrayList<>();
        //排班日期、班次名称
        String scheduleDate = "";
        String shiftName = "";
        Map<String, Object> shiftInfo;
        Map<String, Object> toImportItem;
        for (int i = 1; i <= monthDays; i++) {
            shiftName = Util.null2String(singleCheck.get(String.valueOf(i)));
            scheduleDate = i < 10 ? yearMonth + "-0" + i : yearMonth + "-" + i;
            //获取班次id
            shiftInfo = (Map<String, Object>) shiftMapWithMc.get(shiftName);
            if (!"".equals(shiftName) && shiftInfo == null) {
                Map<String, String> errorMessageMap = new HashMap<>();
                errorMessageMap.put("message", rowIndex + "班次名称-" + shiftName + ", 找不到对应的班次信息，检查是否编辑有误！");
                excelComments.add(errorMessageMap);
                isError = true;
            }
            if (!isError) {
                toImportItem = new HashMap<>();
                if ("".equals(shiftName))  {
                    //设置排班数据
                    toImportItem.put("sfxx", "1");
                    toImportItem.put("bcxx", null);
                } else {
                    //设置排班数据
                    toImportItem.put("sfxx", shiftInfo.get("sfxx").toString());
                    toImportItem.put("bcxx", shiftInfo.get("id").toString());
                }
                toImportItem.put("formmodeid",formModeId);
                toImportItem.put("modeuuid", UUID.randomUUID().toString());
                toImportItem.put("modedatacreater","1");
                toImportItem.put("modedatacreatertype","0");
                toImportItem.put("modedatacreatedate", DateUtil.getCurrentTime().split(" ")[0]);
                toImportItem.put("modedatacreatetime",DateUtil.getCurrentTime().split(" ")[1]);

//                toImportItem.put("szjg", );
                toImportItem.put("pbtj", SchedulingApproachEnum.IMPORT.getKey());
                toImportItem.put("dxlx", ApplicableOrganizationEnum.PERSONNEL.getKey());
                toImportItem.put("bcrq", scheduleDate);
                toImportItem.put("rqlx", rqlxInfoWithRq.get(scheduleDate));
                toImportItem.put("sfdkpp", "0");
                toImportItem.put("pbrq", DateUtil.getCurrentDate());
                toImportItem.put("pbsj", DateUtil.getCurrentTime("yyyy-MM-dd HH:mm").split(" ")[1]);
                toImportItem.put("pbdxry", employeeId);

                singleToImportScheduleInfos.add(toImportItem);
            }
        }
        if (!isError) {
            empIds.add(employeeId);
            toImportScheduleInfos.addAll(singleToImportScheduleInfos);
        }

        return isError;
    }

    private List<Map<String, Object>> matchImportEmp(List<Map<String, Object>> employeeByIds, String lastName, String subCompany, String department, String workCode) {
        employeeByIds = employeeByIds.stream().filter(e ->
                (StrUtil.isBlank(workCode) || Objects.equals(Util.null2String(e.get("workcode")), workCode))
                && (StrUtil.isBlank(lastName) || Objects.equals(e.get("lastname").toString(), lastName))
                && (StringUtils.isBlank(department) || Objects.equals(Util.formatMultiLang(Util.null2String(e.get("departmentname")), "" + user.getLanguage()), department))
                && (StringUtils.isBlank(subCompany) || Objects.equals(Util.formatMultiLang(Util.null2String(e.get("subcompanyname")), "" + user.getLanguage()), subCompany)))
                .collect(Collectors.toList());
        return employeeByIds;
    }

    public void handleScheduleImportData(List<Map<String, Object>> toImportScheduleInfos, List<String> empIds, String yearMonth, int monthDays) {
        if (toImportScheduleInfos.size() > 0 && empIds.size() > 0) {
            //获取日期集合
            List<String> dateList = new ArrayList<>();
            for (int i = 1; i <= monthDays; i++) {
                dateList.add(i < 10 ? yearMonth + "-0" + i : yearMonth + "-" + i);
            }
            //删除老数据
            String delSql = " delete from uf_pbjg where dxlx = " + ApplicableOrganizationEnum.PERSONNEL.getKey()
                    + " and bcrq in ('"+String.join("','",dateList)+"') and pbdxry in (" + String.join(",",empIds) + ")";
            boolean delSign = DbTools.update(delSql);
            //插入数据
            boolean insertSign = CommonUtil.insertBatch(toImportScheduleInfos, "uf_pbjg");
        }
    }

    @Override
    public Map<String, Object> previewImportSchedule(ImportParam param) {

        if (StringUtils.isBlank(param.getImageId())) {
            throw new AttendanceRunTimeException("导入文件id为空！");
        }

        Map<String, Object> map = new HashMap<>();

        InputStream fileInputStream = null;
        try {
            fileInputStream = ImageFileManager.getInputStreamById(Integer.parseInt(param.getImageId()));
            Sheet sheet = ExcelSupport.parseFile(fileInputStream, 0, EXCEL_TYPE_XLSX);
            map.put("headers", ExcelSupport.getSheetHeader(sheet, 1));
            map.put("list", ExcelParseHelper.parse2List(sheet, 2, 1));
            return map;

        } finally {
            IOUtils.closeQuietly(fileInputStream);
        }
    }
}
