package cn.estsh.i3plus.ext.mes.apiservice.serviceimpl.busi.jx;

import cn.estsh.i3plus.ext.mes.api.busi.jx.IJxCenterWorkingBoardService;
import cn.estsh.i3plus.ext.mes.pojo.bean.*;
import cn.estsh.i3plus.ext.mes.pojo.util.MesExtConstWords;
import cn.estsh.i3plus.ext.mes.pojo.util.MesExtEnumUtil;
import cn.estsh.i3plus.platform.common.tool.MathOperation;
import cn.estsh.i3plus.platform.common.tool.TimeTool;
import cn.estsh.i3plus.pojo.mes.bean.MesShift;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.text.ParseException;
import java.util.Calendar;
import java.util.List;
import java.util.Map;
import java.util.StringJoiner;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

/**
 * @Author : wangjie
 * @CreateDate : 2022-02-15
 * @Modify:
 **/
@Slf4j
public class JxCenterWorkingBoardWorkDailyService extends JxCenterWorkingBoardCommonService implements IJxCenterWorkingBoardService {

    private IJxCenterWorkingBoardService proxyService0;

    private IJxCenterWorkingBoardService proxyService1;

    private IJxCenterWorkingBoardService proxyService2;

    private IJxCenterWorkingBoardService proxyService;

    public JxCenterWorkingBoardWorkDailyService(IJxCenterWorkingBoardService proxyService0, IJxCenterWorkingBoardService proxyService1, IJxCenterWorkingBoardService proxyService2, IJxCenterWorkingBoardService proxyService) {
        this.proxyService0 = proxyService0;
        this.proxyService1 = proxyService1;
        this.proxyService2 = proxyService2;
        this.proxyService = proxyService;
    }

    @Override
    public Map<String, Object> queryCenterWorkingBoardData(Map<String, Object> dataMap) {

        proxyService0.queryCenterWorkingBoardData(dataMap);

        Map<String, String> partStandardWorkMap = (Map<String, String>)  proxyService1.queryCenterWorkingBoardData(dataMap).get(MesExtConstWords.STANDARD_WORK);
        MesShift shift = (MesShift) proxyService2.queryCenterWorkingBoardData(dataMap).get(MesShift.class.getSimpleName());

        proxyService.queryCenterWorkingBoardData(packProxyCondition(dataMap));

        MesWorkCenterExt workCenterExtDb = (MesWorkCenterExt) dataMap.get(MesWorkCenterExt.class.getSimpleName());
        MesShiftProdCenterPm shiftProdCenterPm = (MesShiftProdCenterPm) dataMap.get(MesShiftProdCenterPm.class.getSimpleName());

        List<MesOutPutStatistics> outPutStatisticsList = (List<MesOutPutStatistics>) dataMap.get(MesOutPutStatistics.class.getSimpleName());
        List<MesAssistOutAndEnter> assistOutAndEnterList = (List<MesAssistOutAndEnter>) dataMap.get(MesAssistOutAndEnter.class.getSimpleName());
        List<MesShiftProdCenterRecord> shiftProdCenterRecordList = (List<MesShiftProdCenterRecord>) dataMap.get(MesShiftProdCenterRecord.class.getSimpleName());

        List<MesShiftProdCenterRecord> dinnerTimeRecordList = getShiftProdCenterRecordList2Dinner(shiftProdCenterRecordList);
        Map<String, List<MesShiftProdCenterRecord>> dinnerTimeRecordMap = getShiftProdCenterRecordMap2Dinner(dinnerTimeRecordList);

        String workTime = (String) dataMap.get(MesExtConstWords.WORK_TIME);
        String shift2StartTime = null == shift ? MesExtConstWords.EMPTY : appendTime(workTime, shift.getStartTime());
        String shift2EndTime = getEndTimeByShift(workTime, shift);
        String record2EndTime = null == shiftProdCenterPm ? MesExtConstWords.EMPTY : shiftProdCenterPm.getWorkEndTime();

        Integer time2TotalShangban = calcTimeSubDinnerTime(shift2StartTime, shift2EndTime, dinnerTimeRecordList);
        Integer time2NonWorking = calcTime2ShiftProdList(getShiftProdCenterRecordListByFlag(shiftProdCenterRecordList, false));
        Integer time2Jiaban = calcTime2JiaBan(shift2EndTime, record2EndTime, dinnerTimeRecordMap);
        Integer time2Working = time2TotalShangban - time2NonWorking;
        Integer atHomeNum = null == shiftProdCenterPm ? MesExtConstWords.ZERO : shiftProdCenterPm.getAtHomeNum();

        Double workQty = null == shiftProdCenterPm ? new Double(0) : shiftProdCenterPm.getWorkerQty();
        Double time2StandardTime = getStandardTime(outPutStatisticsList, partStandardWorkMap);

        BigDecimal energyRate = divThenMul100Format1RoundHalfUp(time2StandardTime, new Double(time2Working));
        BigDecimal utilizationRate = divThenMul100Format1RoundHalfUp(new Double(time2Working), new Double(calcTime2ShiftProdList(getShiftProdCenterRecordListByFlag(shiftProdCenterRecordList, true))));

        dataMap.put("生产线名称", workCenterExtDb.getWorkCenterName());
        dataMap.put("班次名称", null == shift ? MesExtConstWords.EMPTY : shift.getShiftName());

        dataMap.put("日期", dataMap.get(MesExtConstWords.WORK_TIME));
        dataMap.put("上班时间", shift2StartTime);
        dataMap.put("下班时间", shift2EndTime);
        dataMap.put("定时", calcTimeSubDinnerTime(shift2StartTime, shift2EndTime, getShiftProdCenterRecordList2Dinner(dinnerTimeRecordMap, MesExtEnumUtil.SX_DINNER_TYPE.DINNER.getValue())));

        dataMap.put("在籍人数", atHomeNum);
        dataMap.put("出勤人数", workQty.intValue());
        dataMap.put("缺勤人数", null == shiftProdCenterPm ? MesExtConstWords.ZERO : shiftProdCenterPm.getAbsenteeismNum());
        dataMap.put("加班人数", null == shiftProdCenterPm ? MesExtConstWords.ZERO : shiftProdCenterPm.getOvertimeNum());

        dataMap.put("新上班", null == shiftProdCenterPm ? MesExtConstWords.ZERO : shiftProdCenterPm.getNewWorkNum());
        dataMap.put("退职", null == shiftProdCenterPm ? MesExtConstWords.ZERO : shiftProdCenterPm.getQuitWorkNum());
        dataMap.put("借入人数", getAssistWorkQty(assistOutAndEnterList, true).intValue());
        dataMap.put("借出人数", getAssistWorkQty(assistOutAndEnterList, false).intValue());

        dataMap.put("能率", getBigDecimalPercent(energyRate));
        dataMap.put("稼动率", getBigDecimalPercent(utilizationRate));
        dataMap.put("效率", getBigDecimalPercent(format1RounHalfUp(MathOperation.mul(energyRate.doubleValue(), utilizationRate.doubleValue()))));
        dataMap.put("出勤率", getBigDecimalPercent(divThenMul100Format1RoundHalfUp(workQty, new Double(atHomeNum))));
        dataMap.put("人均台数", divFormat1RoundHalfUp(getOutPutStatisticsList2AmountQty(outPutStatisticsList), workQty));

        dataMap.put("标准时间", format1RounHalfUp(time2StandardTime));
        dataMap.put("总上班时间", time2TotalShangban);
        dataMap.put("作业时间", time2Working);
        dataMap.put("非作业时间", time2NonWorking);
        dataMap.put("加班时间", time2Jiaban);

        return clearUselessData(dataMap);
    }

    @Override
    public Map<String, Object> clearUselessData(Map<String, Object> dataMap) {
        dataMap.remove(MesWorkCenterExt.class.getSimpleName());
        dataMap.remove(MesOutPutStatistics.class.getSimpleName());
        dataMap.remove(MesShiftProdCenterRecord.class.getSimpleName());
        dataMap.remove(MesShiftProdCenterPm.class.getSimpleName());
        dataMap.remove(MesAssistOutAndEnter.class.getSimpleName());
        dataMap.remove(MesShift.class.getSimpleName());
        dataMap.remove(MesExtConstWords.STANDARD_WORK);
        dataMap.remove("hasShiftCode");
        return dataMap;
    }

    private Map<String, Object> packProxyCondition(Map<String, Object> dataMap) {
        dataMap.put("hasShiftCode", dataMap.get(MesExtConstWords.SHIFT_CODE));
        return dataMap;
    }

    private Double getAssistWorkQty(List<MesAssistOutAndEnter> assistOutAndEnterList, Boolean flag) {
        if (CollectionUtils.isEmpty(assistOutAndEnterList)) return new Double(0);
        if (flag) return assistOutAndEnterList.stream().filter(o -> (null != o && MesExtEnumUtil.BU_ASSIST_OUT_AND_ENTER_DETAIL.ASSIST_ENTER.getValue() == o.getAssistOutAndEnterDetail())).mapToDouble(MesAssistOutAndEnter::getInfluenceNumber).sum();
        else return assistOutAndEnterList.stream().filter(o -> (null != o && MesExtEnumUtil.BU_ASSIST_OUT_AND_ENTER_DETAIL.ASSIST_ENTER.getValue() != o.getAssistOutAndEnterDetail())).mapToDouble(MesAssistOutAndEnter::getInfluenceNumber).sum();
    }

    private List<MesShiftProdCenterRecord> getShiftProdCenterRecordList2Dinner(List<MesShiftProdCenterRecord> shiftProdCenterRecordList) {
        return CollectionUtils.isEmpty(shiftProdCenterRecordList) ? null : shiftProdCenterRecordList.stream().filter(o -> (null != o && o.getProdCode().contains(MesExtEnumUtil.SX_DINNER_TYPE.DINNER.name()))).collect(Collectors.toList());
    }

    private List<MesShiftProdCenterRecord> getShiftProdCenterRecordList2Dinner(Map<String, List<MesShiftProdCenterRecord>> shiftProdCenterRecordMap, String prodCode) {
        return CollectionUtils.isEmpty(shiftProdCenterRecordMap) ? null : shiftProdCenterRecordMap.get(prodCode);
    }

    private Map<String, List<MesShiftProdCenterRecord>> getShiftProdCenterRecordMap2Dinner(List<MesShiftProdCenterRecord> shiftProdCenterRecordList) {
        return CollectionUtils.isEmpty(shiftProdCenterRecordList) ? null : shiftProdCenterRecordList.stream().filter(o -> null != o).collect(Collectors.groupingBy(MesShiftProdCenterRecord::getProdCode));
    }

    private Integer calcTime2ShiftProdList(List<MesShiftProdCenterRecord> shiftProdCenterRecordList) {
        return CollectionUtils.isEmpty(shiftProdCenterRecordList) ? MesExtConstWords.ZERO :
                shiftProdCenterRecordList.stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getStartTime()) && !StringUtils.isEmpty(o.getEndTime()))).mapToInt(o -> getSecoundsBetweenTime(o.getStartTime(), o.getEndTime())).sum();
    }

    private Integer calcTime2JiaBan(String shift2EndTime, String record2EndTime, Map<String, List<MesShiftProdCenterRecord>> dinnerTimeRecordMap) {
        if (record2EndTime.compareTo(shift2EndTime) <= 0) return MesExtConstWords.ZERO;
        return calcTimeSubDinnerTime(shift2EndTime, record2EndTime, getShiftProdCenterRecordList2Dinner(dinnerTimeRecordMap, MesExtEnumUtil.SX_DINNER_TYPE.DINNER_OT.getValue()));
    }

    private String getEndTimeByShift(String workTime, MesShift shift) {
        if (null == shift) return MesExtConstWords.EMPTY;
        String ymd = shift.getStartTime().compareTo(shift.getEndTime()) <= 0 ? workTime : TimeTool.timeCalc(TimeTool.stringParseToDate(workTime, MesExtConstWords.DATE_FORMAT), Calendar.DATE, 1, MesExtConstWords.DATE_FORMAT);
        return appendTime(ymd, shift.getEndTime());
    }

    private String appendTime(String ymd, String time) {
        return new StringJoiner(MesExtConstWords.ONE_SPACE).add(ymd).add(time).toString();
    }

    private Integer calcTimeSubDinnerTime(String startTime, String endTime, List<MesShiftProdCenterRecord> dinnerTimeRecordList) {
        if (StringUtils.isEmpty(startTime) || StringUtils.isEmpty(endTime)) return MesExtConstWords.ZERO;
        AtomicReference<Integer> dinnerTime = new AtomicReference<>(0);
        if (!CollectionUtils.isEmpty(dinnerTimeRecordList))
            dinnerTimeRecordList.forEach(o -> dinnerTime.updateAndGet(v -> v + calcDinnerTime(startTime, endTime, o)));
        return getSecoundsBetweenTime(startTime, endTime) - dinnerTime.get();
    }

    private Integer calcDinnerTime(String startTime, String endTime, MesShiftProdCenterRecord dinnerTimeRecord) {
        Boolean flag;
        if (dinnerTimeRecord.getStartTime().compareTo(startTime) >= 0 && dinnerTimeRecord.getStartTime().compareTo(endTime) < 0) flag = true;
        else if (dinnerTimeRecord.getEndTime().compareTo(startTime) > 0 && dinnerTimeRecord.getStartTime().compareTo(endTime) <= 0) flag = true;
        else flag = false;
        return !flag ? MesExtConstWords.ZERO : getSecoundsBetweenTime(dinnerTimeRecord.getStartTime(), dinnerTimeRecord.getEndTime());
    }

    private Integer getSecoundsBetweenTime(String startTime, String endTime) {
        try {
            return TimeTool.getSecoundsBetweenTime(2, startTime, endTime);
        } catch (ParseException e) {
            return MesExtConstWords.ZERO;
        }
    }

}
