package com.engine.attendance.workflow.service.impl;

import com.engine.attendance.enums.AccountingUnitEnum;
import com.engine.attendance.enums.AttendanceItemTypeEnum;
import com.engine.attendance.enums.ClassBelongToEnum;
import com.engine.attendance.enums.ClassSegmentTypeEnum;
import com.engine.attendance.workflow.service.AllowanceService;
import com.engine.common.util.CommonUtil;
import com.engine.common.util.DateUtil;
import com.engine.common.util.DbTools;
import com.engine.common.util.Utils;
import com.engine.core.impl.Service;
import weaver.conn.RecordSet;
import weaver.general.BaseBean;
import weaver.general.Util;

import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author: sy
 * @Description: 出勤津贴
 * @Date: 2024/4/2
 **/
public class AllowanceServiceImpl extends Service implements AllowanceService {
    BaseBean bs = new BaseBean();
    @Override
    public Map<String, Object> addAllowanceRecords(Map<String, Object> params) {

        Map<String, Object> result = new HashMap<>();
        try {
            //获取指定生成的人员id列表，如果没有则生成所有人
            String checkEmpIds = Util.null2String(params.get("empIds"));
            List<String> checkEmpIdList = new ArrayList<>();
            if (!checkEmpIds.equals("")) {
                checkEmpIdList = Arrays.asList(checkEmpIds.split(","));
            }
            //获取modeId，考勤方案的modeId
            Map<String,String> formmodeIdMap = Utils.getFormmodeIdMap();
            String modeId = formmodeIdMap.get("uf_jcl_kq_kqfa");
            //查询考勤方案
            String sql = "select * from uf_jcl_kq_kqfa where zt = 0";
            List<Map<String,Object>> data = DbTools.getSqlToList(sql);
            //获取通用津贴类型考勤项目
            List<String> tyAllowanceIds = new ArrayList<>();
            String tyAllowanceSql = "select * from uf_jcl_kq_kqxm where tyxm = 1 and xmlx = 7";
            List<Map<String,Object>> tyAllowanceData = DbTools.getSqlToList(tyAllowanceSql);
            for (Map<String, Object> map : tyAllowanceData) {
                tyAllowanceIds.add(map.get("id").toString());
            }
            bs.writeLog("tyAllowanceIds : " +  tyAllowanceIds);
            //获取人员和津贴类型考勤项目信息，构建映射关系
            Map<String, List<String>> empIdWithAllowanceInfo = new HashMap<>();
            List<String> targetEmpIdList = new ArrayList<>();
            List<String> targetAllowanceIdList = new ArrayList<>();
            List<String> targetBcIdList = new ArrayList<>();
            if (tyAllowanceIds.size() > 0) {
                targetAllowanceIdList.addAll(tyAllowanceIds);
            }
            for (Map<String, Object> map : data) {
                String dataId = map.get("id").toString();
                //获取方案适用的人员id列表
                List<String> empIdList = CommonUtil.getEmpIds(dataId, modeId);
                //获取津贴类型的考勤项目
                String dtSql = "select * from uf_jcl_kq_kqfa_dt1 a left join uf_jcl_kq_kqxm b on b.id = a.kqxm where a.mainid = " + dataId
                        + " and b.xmlx = " + AttendanceItemTypeEnum.ALLOWANCE.getKey();
                List<Map<String,Object>> dtData = DbTools.getSqlToList(dtSql);
                List<String> allowanceIdList = new ArrayList<>();
                dtData.forEach(f -> allowanceIdList.add(f.get("kqxm").toString()));
                if (allowanceIdList.size() > 0 && empIdList.size() > 0) {
                    targetEmpIdList.addAll(empIdList);
                    targetAllowanceIdList.addAll(allowanceIdList);
                    //构建映射
                    empIdList.forEach(f -> {
                        List<String> valueIdList = new ArrayList<>();
                        if (empIdWithAllowanceInfo.get(f) == null) {
                            empIdWithAllowanceInfo.put(f, allowanceIdList);
                            if (tyAllowanceIds.size() > 0) {
                                valueIdList.addAll(allowanceIdList);
                                valueIdList.addAll(tyAllowanceIds);
                                empIdWithAllowanceInfo.put(f, valueIdList);
                            }
                        } else {
                            valueIdList = empIdWithAllowanceInfo.get(f);
                            valueIdList.addAll(allowanceIdList);
                            empIdWithAllowanceInfo.put(f, valueIdList);
                        }
                    });
                }
            }
            //20240515产品需求变更，即使考勤方案未设置适用范围，对于通用津贴类型考勤项目，也要适用于全员
            if (tyAllowanceIds.size() > 0) {
                String empSql = "select id from hrmresource where 1=1 ";
                if (targetEmpIdList.size() > 0) {
                    empSql = empSql + " and id not in (" + String.join(",",targetEmpIdList) + ")";
                }
                List<Map<String, Object>> empData = DbTools.getSqlToList(empSql);
                for (Map<String, Object> empInfo : empData) {
                    targetEmpIdList.add(empInfo.get("id").toString());
                    empIdWithAllowanceInfo.put(empInfo.get("id").toString(), tyAllowanceIds);
                }
            }
            //构建班次和津贴映射关系
            Map<String, Map<String, Object>> allowanceIdWithKqxmInfo = new HashMap<>();
            Map<String, List<String>> bcWithAllowanceInfo = new HashMap<>();
            if (targetAllowanceIdList.size() > 0) {
                //去重
                targetAllowanceIdList = targetAllowanceIdList.stream().distinct().collect(Collectors.toList());
                //构建映射
                String allowanceWithBcSql = "select * from uf_jcl_kq_kqxm where id in ("+String.join(",",targetAllowanceIdList) + ") and sydbc is not null ";
                List<Map<String, Object>> allowanceWithBcData = DbTools.getSqlToList(allowanceWithBcSql);
                for (Map<String, Object> map : allowanceWithBcData) {
                    String bcArr = map.get("sydbc").toString();
                    String allowanceId = map.get("id").toString();
                    allowanceIdWithKqxmInfo.put(allowanceId, map);
                    List<String> bcList = Arrays.asList(bcArr.split(","));
                    targetBcIdList.addAll(bcList);
                    bcList.forEach(f -> {
                        List<String> values = new ArrayList<>();
                        if (bcWithAllowanceInfo.get(f) == null) {
                            values.add(allowanceId);
                            bcWithAllowanceInfo.put(f, values);
                        } else {
                            values = bcWithAllowanceInfo.get(f);
                            values.add(allowanceId);
                            bcWithAllowanceInfo.put(f, values);
                        }
                    });
                }
            }
            //获取出勤结果，遍历处理津贴信息
            String startDate = Util.null2String(params.get("startDate"));
            String endDate = Util.null2String(params.get("endDate"));
            List<Map<String, Object>> cqData = new ArrayList<>();
            //如果入参中选中了人员，则只处理选中的人
            if (checkEmpIdList.size() > 0) {
                List<String> finalCheckEmpIdList = checkEmpIdList;
                targetEmpIdList = targetEmpIdList.stream().filter(f -> finalCheckEmpIdList.contains(f)).collect(Collectors.toList());
            }
            if (targetEmpIdList.size() > 0 && targetBcIdList.size() > 0) {
                //去重
                targetBcIdList = targetBcIdList.stream().distinct().collect(Collectors.toList());
                //查询
                String cqSql = "select * from uf_jcl_kq_cqjg where ygid in ("+String.join(",",targetEmpIdList) + ") and rq >= '" + startDate +"'" + " and rq <= '" + endDate +"'"
                        + " and bc in ("+String.join(",",targetBcIdList) + ")";
                cqData = DbTools.getSqlToList(cqSql);
            }
            bs.writeLog("cqData_size : " +  cqData.size());
            //获取待新增的津贴数据
            List<Map<String, String>> allowanceInfoList = createAllowanceInfo(cqData, empIdWithAllowanceInfo, bcWithAllowanceInfo, allowanceIdWithKqxmInfo);
            bs.writeLog("allowanceInfoList_size : " +  allowanceInfoList.size());
            //新增津贴数据，先删后加
            String delSql = "delete from uf_jcl_kq_cqjt where rq >= '" + startDate +"'" + " and rq <= '" + endDate +"'"
                    + " and yg in (" + String.join(",",targetEmpIdList) + ") and bc in (" + String.join(",",targetBcIdList) + ")";
            boolean delSign = DbTools.update(delSql);
            bs.writeLog("delSign : " +  delSign + ", delSql : " + delSql);
            if (allowanceInfoList.size() > 0) {
                //插入津贴数据
                List<List> dataList = new ArrayList<>();
                String insertSql = " insert into uf_jcl_kq_cqjt(formmodeid,modeuuid,modedatacreater,modedatacreatertype,modedatacreatedate,modedatacreatetime," +
                        "szjg,yg,rq,bc,jtlx,sc,zt) values(?,?,?,?,?,?,?,?,?,?,?,?,?)";
                String formmodeId = formmodeIdMap.get("uf_jcl_kq_cqjt");
                for (Map<String, String> map : allowanceInfoList) {
                    List<String> list = new ArrayList<>();

                    list.add(formmodeId);
                    list.add(UUID.randomUUID().toString());
                    list.add("1");
                    list.add("0");
                    list.add(DateUtil.getCurrentTime().split(" ")[0]);
                    list.add(DateUtil.getCurrentTime().split(" ")[1]);
                    list.add(map.get("szjg"));
                    list.add(map.get("yg"));
                    list.add(map.get("rq"));
                    list.add(map.get("bc"));
                    list.add(map.get("jtlx"));
                    list.add(map.get("sc"));
                    list.add(map.get("zt"));

                    dataList.add(list);
                }
                bs.writeLog("dataList_size : " +  dataList.size());
                if(dataList.size() > 0){
                    RecordSet rs = new RecordSet();
                    bs.writeLog("津贴数据记录入库开始---");
                    boolean insertSign =rs.executeBatchSql(insertSql,dataList);
                    bs.writeLog("insertSign : " + insertSign);
                    result.put("result", insertSign);
                }
            }

        } catch (Exception e) {
            bs.errorLog("catch error :{}",e);
        }
        return result;
    }

    private List<Map<String, String>> createAllowanceInfo(List<Map<String, Object>> cqData, Map<String, List<String>> empIdWithAllowanceInfo, Map<String
            , List<String>> bcWithAllowanceInfo, Map<String, Map<String, Object>> allowanceIdWithKqxmInfo) {
        List<Map<String, String>> allowanceInfoList = new ArrayList<>();
        Map<String, String> allowanceInfoItem;
        //获取加班类型的考勤项目，并构建项目id和核算单位映射关系
        Map<String, String> jbKqxmUnitInfo = collectKqxmUnitInfo(AttendanceItemTypeEnum.WORK_OVERTIME.getKey());
        //获取津贴类型的考勤项目，并构建项目id和核算单位映射关系
        Map<String, String> jtKqxmUnitInfo = collectKqxmUnitInfo(AttendanceItemTypeEnum.ALLOWANCE.getKey());
        //获取津贴类型的考勤项目，并构建项目id和核算量映射关系
        Map<String, String> jtKqxmCountScaleInfo = collectKqxmCountScaleInfo(AttendanceItemTypeEnum.ALLOWANCE.getKey());
        //获取班次对应的班段明细数据
        Map<String, List<Map<String, Object>>> shiftIdToDetailInfo = collectShiftIdToDetailInfo();
        //获取班次对应的开始时间
        Map<String, String> shiftIdToStartInfo = collectShiftIdToStartInfo();
        //遍历出勤结果
        for (Map<String, Object> map : cqData) {
            String empId = map.get("ygid").toString();
            String bc = Util.null2String(map.get("bc"));
            //判断该班次是否存在津贴
            List<String> allowanceIdsByBc = bcWithAllowanceInfo.get(bc);
            //判断该人员是否有相关的津贴
            List<String> allowanceIdsByEmp = empIdWithAllowanceInfo.get(empId);
            //处理该人员在该班次可生效的津贴
            if(allowanceIdsByBc != null && allowanceIdsByEmp != null) {
                //取交集
                allowanceIdsByBc = allowanceIdsByBc.stream()
                        .filter(allowanceIdsByEmp::contains)
                        .collect(Collectors.toList());
                if (allowanceIdsByBc.size() == 0) {
                    continue;
                }
                //收集下出勤结果中项目1-8存在的项目id
                List<String> kqxmIdsWithCq = collectKqxmIdsByCq(map);
                //收集下出勤结果中进出时间，仅收集进出两个时间点都有的数据
                List<Map<String, String>> jcInfoList = collectJcInfoByCq(map);
                //收集下出勤结果中，项目1-8中累积的加班时长，处理成分钟数
                Integer overtimeMinutes = collectOvertimeMinutes(map, jbKqxmUnitInfo);
                bs.writeLog("overtimeMinutes : " +  overtimeMinutes);
                //最终核算分钟数
                double countMinutes = 0;
                //出勤时长
                double cqsc = Util.null2String(map.get("cqsc")).equals("") ? 0 : Double.parseDouble(map.get("cqsc").toString());
                //出勤日期
                String cqRq = Util.null2String(map.get("rq"));
                //获取班次班段时间范围,todo,出勤结果中班次班段数据要考虑到跨天情况
                List<Map<String, String>> bcTimeRangeList = collectBcTimeRangeInfo(shiftIdToDetailInfo.get(bc), cqRq);
                //遍历该出勤结果中班次、人员都关联的津贴项目
                for(String allowanceId : allowanceIdsByBc) {
                    Map<String, Object> allowanceInfo = allowanceIdWithKqxmInfo.get(allowanceId);
                    //项目1-8中出现以下考勤项目时，津贴失效
                    String banKqxm = Util.null2String(allowanceInfo.get("bxsdxm"));
                    List<String> banKqxmList = new ArrayList<>();
                    if (!banKqxm.equals("")) {
                        banKqxmList = Arrays.asList(banKqxm.split(","));
                    }
                    //是否需要审核标识，,0-否，1-是
                    String checkSign = Util.null2String(allowanceInfo.get("sfxysh"));
                    //正常工作时长计入核算量_标识,0-否，1-是
                    String includeDailyWorkHours = Util.null2String(allowanceInfo.get("ljbcngzsj"));
                    //检查特定时间点是否在岗_标识,0-否，1-是
                    String checkOneTimeOnDuty = Util.null2String(allowanceInfo.get("xysjd"));
                    //特定在岗时间点
                    String onDutyTime = Util.null2String(allowanceInfo.get("sjd"));
                    //判断特定在岗时间点指向日期
                    String onDutyDate = getOnDutyDate(shiftIdToStartInfo.get(bc), onDutyTime, cqRq);
                    //时间点之前的时长也计入核算量_标识,0-否，1-是
                    String includeHoursBeforeDutyTime = Util.null2String(allowanceInfo.get("jljxysjdzqdsc"));
                    //起算分钟数(不包含)
                    String startMinutes = Util.null2String(allowanceInfo.get("jtqsfzs"));
                    //最大核算分钟数（包含）
                    String maxMinutes = Util.null2String(allowanceInfo.get("zdhsfzs"));
                    //超出起算时长的单次累加分钟数
                    String oneTimeAddMinutes = Util.null2String(allowanceInfo.get("cchsfzs"));
                    bs.writeLog("includeDailyWorkHours : " +  includeDailyWorkHours + ",checkOneTimeOnDuty : " +  checkOneTimeOnDuty
                                    + ",onDutyTime : " +  onDutyTime + ",includeHoursBeforeDutyTime : " +  includeHoursBeforeDutyTime
                                    + ",startMinutes : " +  startMinutes,"maxMinutes : " +  maxMinutes + ",oneTimeAddMinutes : " +  oneTimeAddMinutes);
                    //逐一判断是否满足津贴时长计入规则
                    //1-此为考勤项目的多选，如果员工当天出勤中的项目1~项目8存在不核算此津贴的项目，则员工不能获得此津贴
                    //取交集
                    banKqxmList = banKqxmList.stream()
                            .filter(kqxmIdsWithCq::contains)
                            .collect(Collectors.toList());
                    if (banKqxmList.size() > 0) {
                        continue;
                    }
                    //2-如果勾选“检查特定时间点是否在岗”，则需要判断员工当天“须要在岗的时间点”所设置的时间员工是否在岗
                    if (checkOneTimeOnDuty.equals("1") && !onDutyTime.equals("")) {
                        boolean onDuty = false;
                        //将特殊在岗时间点拼接上日期
                        String onDutyTimeWithDate = onDutyDate + " " + onDutyTime;
                        for (Map<String, String> jcInfo : jcInfoList) {
                            if (onDutyTimeWithDate.compareTo(jcInfo.get("signIn")) >= 0 && onDutyTimeWithDate.compareTo(jcInfo.get("signOut")) <= 0) {
                                onDuty = true;
                                break;
                            }
                        }
                        //不在岗，直接处理下一个津贴
                        if (!onDuty) {
                            continue;
                        }
                        //3-如果时长大于“起算分钟数（不包含）”小于等于“最大核算分钟数（包含）”，则员工或获得此津贴
                        //a-时长默认为取当天所有项目1~项目8中的各加班类型的考勤项目对应的时长
                        //b-如果勾选“工作时长也计入核算量”，则还需要累加当天的“出勤时长”字段值
                        //c-一旦勾选了“检查特定时间点是否在岗”，且只取“时间点”之后的分钟数时长
                        //d-如果勾选了“时间点之前的时长也计入核算量”则上一点不需要做

                        if (includeHoursBeforeDutyTime.equals("1")) {
                            countMinutes = overtimeMinutes;
                            if (includeDailyWorkHours.equals("1")) {
                                countMinutes = countMinutes + cqsc * 60;
                            }
                        } else {
                            countMinutes = getMinutesWithAfterPointTime(cqRq, bcTimeRangeList, jcInfoList, overtimeMinutes, onDutyTimeWithDate, includeDailyWorkHours);
                        }
                    } else {
                        //未勾选“检查特定时间点是否在岗”
                        countMinutes = overtimeMinutes;
                        if (includeDailyWorkHours.equals("1")) {
                            countMinutes = countMinutes + cqsc * 60;
                        }
                    }
                    //4-津贴时长计算规则
                    //a-起算分钟数 + 超出起算时长的单次累加分钟数 * N <= 最大核算分钟数
                    //b-由a点获取到分钟数后，要根据津贴项目的核算量+核算单位来获取最终津贴时长，例如分钟数170分钟，核算量为0.5，核算单位为小时，则最终核算时长为2.5小时
                    double allowanceMinutes = 0;
                    bs.writeLog("countMinutes : " +  countMinutes);
                    if (countMinutes > Double.parseDouble(startMinutes)) {
                        if (!oneTimeAddMinutes.equals("") && !oneTimeAddMinutes.equals("0")) {
                            double multiple = (countMinutes - Double.parseDouble(startMinutes)) / Double.parseDouble(oneTimeAddMinutes);
                            allowanceMinutes = Double.parseDouble(startMinutes) + Double.parseDouble(oneTimeAddMinutes) * Math.floor(multiple);
                        } else {
                            allowanceMinutes = Double.parseDouble(startMinutes);
                        }
                        if (allowanceMinutes > Double.parseDouble(maxMinutes)) {
                            allowanceMinutes = Double.parseDouble(maxMinutes);
                        }
                        bs.writeLog("allowanceMinutes : " +  allowanceMinutes);
                        //津贴时长
                        String allowanceUnit = Util.null2String(jtKqxmUnitInfo.get(allowanceId));
                        String countScale = Util.null2String(jtKqxmCountScaleInfo.get(allowanceId));
                        if (!countScale.equals("")) {
                            double sc = 0;
                            if (allowanceUnit.equals(AccountingUnitEnum.DAY.getKey())) {
                                sc = (allowanceMinutes - allowanceMinutes % (1440 * Double.parseDouble(countScale))) / 1440;
                            } else if (allowanceUnit.equals(AccountingUnitEnum.HOUR.getKey())) {
                                sc = (allowanceMinutes - allowanceMinutes % (60 * Double.parseDouble(countScale))) / 60;
                            } else if (allowanceUnit.equals(AccountingUnitEnum.MINUTES.getKey())) {
                                sc = allowanceMinutes - allowanceMinutes % Double.parseDouble(countScale);
                            }
                            bs.writeLog("sc : " +  sc);
                            //记录待新增的津贴记录
                            allowanceInfoItem = new HashMap<>();
                            allowanceInfoItem.put("szjg", Util.null2String(map.get("szjg")));
                            allowanceInfoItem.put("yg", Util.null2String(map.get("ygid")));
                            allowanceInfoItem.put("rq", cqRq);
                            allowanceInfoItem.put("bc", Util.null2String(map.get("bc")));
                            allowanceInfoItem.put("jtlx", allowanceId);
                            //不需要审核的话，直接就是已审核状态
                            allowanceInfoItem.put("zt", !"1".equals(checkSign) ? "1" : "0");
                            if (!allowanceUnit.equals(AccountingUnitEnum.ONCE.getKey())) {
                                allowanceInfoItem.put("sc", String.format("%.2f", sc));
                            } else {
                                allowanceInfoItem.put("sc", "1");
                            }
                            allowanceInfoList.add(allowanceInfoItem);
                        }
                    }
                }
            }
        }
        return allowanceInfoList;
    }

    private Map<String, String> collectShiftIdToStartInfo() {
        Map<String, String> shiftIdToStartInfo = new HashMap<>();
        String sql = "select * from uf_jcl_kq_bcxx";
        List<Map<String, Object>> data = DbTools.getSqlToList(sql);
        for (Map<String, Object> item : data) {
            shiftIdToStartInfo.put(item.get("id").toString(), item.get("kssj").toString());
        }
        return shiftIdToStartInfo;
    }

    /**
     * 获取班次明细表中班段类型为工作时段的数据，并映射成key为班次id的对象
     * @return
     */
    private Map<String, List<Map<String, Object>>> collectShiftIdToDetailInfo() {
        Map<String, List<Map<String, Object>>> shiftIdToDetailInfo = new HashMap<>();
        String sql = "select * from uf_jcl_kq_bcxx_dt1 where bdlx = " + ClassSegmentTypeEnum.WORK_TIME.getKey();
        List<Map<String, Object>> detailList = DbTools.getSqlToList(sql);
        if (detailList.size() > 0) {
            shiftIdToDetailInfo = detailList.stream().collect(Collectors.groupingBy(
                            map -> (String) map.get("mainid"),
                            Collectors.mapping(map -> map, Collectors.toList())));
        }
        return shiftIdToDetailInfo;

    }


    /**
     * 特定在岗时间点指向日期
     * @param bcStartTime 班次开始时间
     * @param onDutyTime 特殊在岗时间点
     * @param cqRq 出勤结果中出勤日期
     * @return
     */
    private String getOnDutyDate(String bcStartTime, String onDutyTime, String cqRq) {
        boolean currentDateSign = false;
        if ("".equals(onDutyTime) || onDutyTime.compareTo(bcStartTime) >= 0) {
            currentDateSign = true;
        }
        if (currentDateSign) {
            return cqRq;
        } else {
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); // 时间格式
            LocalDate date = LocalDate.parse(cqRq, formatter); // 解析为LocalDate对象
            LocalDate nextDay = date.plusDays(1); // 将日期加一天
            return nextDay.format(formatter);
        }
    }

    /**
     * 获取考虑特殊在岗时间点情况下的考核时长分钟数
     * 勾选在岗时间点时，
     * 1-处于班次工作时间段时，结合进出时间和班次班段判断班段时间内实际工作分钟数
     * 2-处于加班时间段内，结合进出时间记录，累加
     * @param overtimeMinutes
     * @param onDutyTimeWithDate
     * @return
     */
    private double getMinutesWithAfterPointTime(String cqRq, List<Map<String, String>> bcTimeRangeList, List<Map<String, String>> jcInfoList,
                                                Integer overtimeMinutes, String onDutyTimeWithDate, String includeDailyWorkHours) {
        double bcOnDutyMinutes = 0;
        double realOverWorkMinutes = 0;
        if (includeDailyWorkHours.equals("1")) {
            //判断在岗时间点和班次班段的关系，存在包含关系，则计算出班次时间内需要累计的时间
            //首先获取班次班段设置和实际进出交集的时间段
            List<Map<String, String>> bcRealOnDutyTimeRange = new ArrayList<>();
            Map<String, String> realItemMap;
            for (Map<String, String> bcTime : bcTimeRangeList) {
                String realStartTime = "";
                String realEndTime = "";
                //取班次开始和结束时间
                String startTime = bcTime.get("startTime");
                String endTime = bcTime.get("endTime");
                for (Map<String, String> jcTime : jcInfoList) {
                    String signInTime = jcTime.get("signIn");
                    String signOutTime = jcTime.get("signOut");
                    if (startTime.compareTo(signInTime) >= 0 && startTime.compareTo(signOutTime) <= 0) {
                        realStartTime = startTime;
                    }
                    if (endTime.compareTo(signInTime) >= 0 && endTime.compareTo(signOutTime) <= 0) {
                        realEndTime = endTime;
                    }
                    if (startTime.compareTo(signInTime) < 0 && endTime.compareTo(signOutTime) > 0) {
                        realStartTime = signInTime;
                        realEndTime = signOutTime;
                    }
                    if (realStartTime.equals("") && !realEndTime.equals("")) {
                        realStartTime = signInTime;
                    }
                    if (!realStartTime.equals("") && realEndTime.equals("")) {
                        realEndTime = signOutTime;
                    }
                    if (!realStartTime.equals("") && !realEndTime.equals("")) {
                        realItemMap = new HashMap<>();
                        realItemMap.put("startTime", realStartTime);
                        realItemMap.put("endTime", realEndTime);
                        bcRealOnDutyTimeRange.add(realItemMap);
                    }
                }
            }
            //遍历获取班次班段时间内的累计时长（某一在岗时间点之后的时间）
            for (Map<String, String> bcRealTimeInfo : bcRealOnDutyTimeRange) {
                if (onDutyTimeWithDate.compareTo(bcRealTimeInfo.get("startTime")) <= 0) {
                    bcOnDutyMinutes = bcOnDutyMinutes + getMinutesByTwo(bcRealTimeInfo.get("startTime"), bcRealTimeInfo.get("endTime"));
                } else if (onDutyTimeWithDate.compareTo(bcRealTimeInfo.get("startTime")) >= 0 && onDutyTimeWithDate.compareTo(bcRealTimeInfo.get("endTime")) <= 0) {
                    bcOnDutyMinutes = bcOnDutyMinutes + getMinutesByTwo(onDutyTimeWithDate, bcRealTimeInfo.get("endTime"));
                }
            }
        }
        //判断在岗时间点和加班时间区间的关系，即进出打卡记录是否与在岗时间点有包含关系，分情况累计时间
        for (Map<String, String> jcInfo : jcInfoList) {
            if (onDutyTimeWithDate.compareTo(jcInfo.get("signIn")) <= 0) {
                realOverWorkMinutes = realOverWorkMinutes + getMinutesByTwo(jcInfo.get("signIn"), jcInfo.get("signOut"));
            } else if (onDutyTimeWithDate.compareTo(jcInfo.get("signIn")) >= 0 && onDutyTimeWithDate.compareTo(jcInfo.get("signOut")) <= 0) {
                realOverWorkMinutes = realOverWorkMinutes + getMinutesByTwo(onDutyTimeWithDate, jcInfo.get("signOut"));
            }
        }
        //实际加班时长累计的核算分钟数，不可以超过项目1-8累计的加班时长分钟数
        if (realOverWorkMinutes > overtimeMinutes) {
            realOverWorkMinutes = overtimeMinutes;
        }
        return realOverWorkMinutes + bcOnDutyMinutes;
    }

    private double getMinutesByTwo(String startTime, String endTime) {
        List<String> startInfoList = Arrays.asList(startTime.split("\\s+|-|:"));
        List<String> endInfoList = Arrays.asList(endTime.split("\\s+|-|:"));

        LocalDateTime dateTime1 = LocalDateTime.of(Integer.parseInt(startInfoList.get(0)),
                Integer.parseInt(replaceFirstChar(startInfoList.get(1),"0")),
                Integer.parseInt(replaceFirstChar(startInfoList.get(2),"0")),
                Integer.parseInt(replaceFirstChar(startInfoList.get(3),"0")),
                Integer.parseInt(replaceFirstChar(startInfoList.get(4),"0")));
        LocalDateTime dateTime2  = LocalDateTime.of(Integer.parseInt(endInfoList.get(0)),
                Integer.parseInt(replaceFirstChar(endInfoList.get(1),"0")),
                Integer.parseInt(replaceFirstChar(endInfoList.get(2),"0")),
                Integer.parseInt(replaceFirstChar(endInfoList.get(3),"0")),
                Integer.parseInt(replaceFirstChar(endInfoList.get(4),"0")));

        Duration duration = Duration.between(dateTime1, dateTime2);
        // 获取分钟数
        return duration.toMinutes();
    }
    public static String replaceFirstChar(String original, String target) {
        int index = original.indexOf(target);
        if ("00".equals(original) || index == -1) {
            return original; // 如果没有找到目标字符，返回原字符串
        } else if (index == 0) {
            return original.substring(1);
        } else {
            return original;
        }
    }

    /**
     * 根据班次班段详细数据中
     * 班段类型、归属日、班段开始结束时间获取班段中多个年月日时分的时间点
     * @return
     */
    private List<Map<String, String>> collectBcTimeRangeInfo(List<Map<String, Object>> bcDetailList, String cqRq) {
        List<Map<String, String>> timeRangeInfo = new ArrayList<>();
//        if (!bcbdxx.equals("")) {
//            List<String> rangeList = Arrays.asList(bcbdxx.split("\\|"));
//            Map<String, String> itemMap;
//            for (String range : rangeList) {
//                String[] timeInfo = range.split("-");
//                itemMap = new HashMap<>();
//                itemMap.put("startTime", timeInfo[0]);
//                itemMap.put("endTime", timeInfo[1]);
//                timeRangeInfo.add(itemMap);
//            }
//        }
        if (bcDetailList != null && bcDetailList.size() > 0) {
            String bcDate = "";
            Map<String, String> itemMap;
            for (Map<String, Object> detailItem : bcDetailList) {
                bcDate = cqRq;
                String belongDayType = Util.null2String(detailItem.get("gsrq"));
                String startTime = Util.null2String(detailItem.get("kssj"));
                String endTime = Util.null2String(detailItem.get("jssj"));
                if (belongDayType.equals(ClassBelongToEnum.YESTERDAY.getKey())) {
                    bcDate = DateUtil.beforeDay(bcDate,1);
                } else if (belongDayType.equals(ClassBelongToEnum.NEXTDAY.getKey())) {
                    bcDate = DateUtil.AfterDay(bcDate,1);
                }
                if (!"".equals(startTime) && !"".equals(endTime)) {
                    itemMap = new HashMap<>();
                    itemMap.put("startTime", bcDate + " " + startTime);
                    if (startTime.compareTo(endTime) >= 0) {
                        itemMap.put("endTime", DateUtil.AfterDay(bcDate,1) + " " + endTime);
                    } else {
                        itemMap.put("endTime", bcDate + " " + endTime);
                    }
                    timeRangeInfo.add(itemMap);
                }
            }
        }
        return timeRangeInfo;
    }

    private Map<String, String> collectKqxmUnitInfo(String kqxmType) {
        Map<String, String> unitInfo = new HashMap<>();
        String sql = "select * from uf_jcl_kq_kqxm where xmlx = " + kqxmType;
        List<Map<String,Object>> data = DbTools.getSqlToList(sql);
        for (Map<String, Object> map : data) {
            unitInfo.put(map.get("id").toString(), Util.null2String(map.get("hsdw")));
        }
        return unitInfo;
    }

    private Map<String, String> collectKqxmCountScaleInfo(String kqxmType) {
        Map<String, String> unitInfo = new HashMap<>();
        String sql = "select * from uf_jcl_kq_kqxm where xmlx = " + kqxmType;
        List<Map<String,Object>> data = DbTools.getSqlToList(sql);
        for (Map<String, Object> map : data) {
            unitInfo.put(map.get("id").toString(), Util.null2String(map.get("hsl")));
        }
        return unitInfo;
    }

    private Integer collectOvertimeMinutes(Map<String, Object> cqMap, Map<String, String> jbKqxmUnitInfo) {
        double minutes = 0;
        String xm = "";
        String sc = "";
        String unit = "";
        Map<String, Integer> unitToMinutes = new HashMap<>();
        unitToMinutes.put(AccountingUnitEnum.DAY.getKey(), 1440);
        unitToMinutes.put(AccountingUnitEnum.HOUR.getKey(), 60);
        unitToMinutes.put(AccountingUnitEnum.MINUTES.getKey(), 1);
        unitToMinutes.put(AccountingUnitEnum.ONCE.getKey(), 0);
        for (int i = 1; i <= 8; i++) {
           xm = Util.null2String(cqMap.get("xm" + i));
           sc = Util.null2String(cqMap.get("sc" + i));
           unit = Util.null2String(jbKqxmUnitInfo.get(xm));
           if (!xm.equals("") && !sc.equals("") && !unit.equals("")) {
               minutes = minutes + Double.parseDouble(sc) * unitToMinutes.get(unit);
           }
        }
        return (int) Math.round(minutes);
    }

    private List<Map<String, String>> collectJcInfoByCq(Map<String, Object> cqMap) {
        List<Map<String, String>> jcInfoList = new ArrayList<>();
        String singIn = "";
        String signOut = "";
        Map<String, String> itemMap;
        for (int i = 1; i <= 8; i++) {
            singIn = Util.null2String(cqMap.get("j" + i));
            signOut = Util.null2String(cqMap.get("c" + i));
            if (!singIn.equals("") && !signOut.equals("")) {
                itemMap = new HashMap<>();
                itemMap.put("signIn", singIn.substring(0, 16));
                itemMap.put("signOut", signOut.substring(0, 16));
                jcInfoList.add(itemMap);
            } else if (singIn.equals("") && signOut.equals("")){
                break;
            }
        }
        return jcInfoList;
    }

    private List<String> collectKqxmIdsByCq(Map<String, Object> cqMap) {
        List<String> kqxmIdsWithCq = new ArrayList<>();
        String xmId = "";
        for (int i = 1; i <= 8; i++) {
            xmId = Util.null2String(cqMap.get("xm" + i));
            if (!xmId.equals("")) {
                kqxmIdsWithCq.add(xmId);
            } else {
                break;
            }
        }
        return kqxmIdsWithCq;

    }
}
