package cn.estsh.i3plus.ext.mes.apiservice.serviceimpl.base;

import cn.estsh.i3plus.ext.mes.api.base.IMesEpAssistOutAndEnterService;
import cn.estsh.i3plus.ext.mes.apiservice.dao.IMesAssistOutAndEnterDao;
import cn.estsh.i3plus.ext.mes.pojo.bean.MesAssistOutAndEnter;
import cn.estsh.i3plus.ext.mes.pojo.model.MesAssistOutAndEnterDateSumModel;
import cn.estsh.i3plus.ext.mes.pojo.repository.MesAssistOutAndEnterRepository;
import cn.estsh.i3plus.ext.mes.pojo.sqlpack.MesExtHqlPack;
import cn.estsh.i3plus.ext.mes.pojo.util.MesExtConstWords;
import cn.estsh.i3plus.ext.mes.pojo.util.MesExtEnumUtil;
import cn.estsh.i3plus.mes.apiservice.util.DateUtil;
import cn.estsh.i3plus.platform.common.convert.ConvertBean;
import cn.estsh.i3plus.platform.common.exception.ImppExceptionEnum;
import cn.estsh.i3plus.platform.common.tool.TimeTool;
import cn.estsh.i3plus.pojo.base.bean.DdlPackBean;
import cn.estsh.i3plus.pojo.base.bean.ListPager;
import cn.estsh.i3plus.pojo.base.common.Pager;
import cn.estsh.i3plus.pojo.base.common.PagerHelper;
import cn.estsh.i3plus.pojo.base.enumutil.CommonEnumUtil;
import cn.estsh.impp.framework.boot.exception.ImppExceptionBuilder;
import cn.estsh.impp.framework.boot.util.ValidatorBean;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

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

/**
 * @author wangjie
 * @version 1.0
 * @date 2021/1/13 9:28
 **/
@Slf4j
@Service
public class MesEpAssistOutAndEnterService implements IMesEpAssistOutAndEnterService {


    @Autowired
    private MesAssistOutAndEnterRepository assistOutAndEnterRepository;

    @Autowired
    private IMesAssistOutAndEnterDao assistOutAndEnterDao;

    @Override
    public ListPager<MesAssistOutAndEnter> queryAssistOutAndEnterPager(MesAssistOutAndEnter assistOutAndEnter, Pager pager) {
        DdlPackBean hqlPack = MesExtHqlPack.getAssistOutAndEnter(assistOutAndEnter);
        pager = PagerHelper.getPager(pager, assistOutAndEnterRepository.findByHqlWhereCount(hqlPack));
        hqlPack.setOrderByStr(" order by createDatetime Desc ");
        List<MesAssistOutAndEnter> AssistOutAndEnterList = assistOutAndEnterRepository.findByHqlWherePage(hqlPack, pager);
        return new ListPager(AssistOutAndEnterList, pager);
    }

    @Override
    public void insertAssistOutAndEnter(MesAssistOutAndEnter assistOutAndEnter) {
        List<MesAssistOutAndEnter> assistOutAndEnterList = new ArrayList<>();
        if(assistOutAndEnter.getAssistOutAndEnterDetail() == MesExtEnumUtil.ASSIST_OUT_AND_ENTER_DETAIL.MAKE_ASSIST_OUT.getValue()){
            ValidatorBean.checkNotNull(assistOutAndEnter.getAssistWorkCenterCode(), "当前援入援出明细项为制造援出,援入产线必填");
            MesAssistOutAndEnter assistEnter = new MesAssistOutAndEnter();
            String[] ignoreProps = {"assistWorkCenterCode", "assistWorkCenterName"};
            BeanUtils.copyProperties(assistOutAndEnter, assistEnter,ignoreProps);
            assistEnter.setAssistOutAndEnterDetail(MesExtEnumUtil.ASSIST_OUT_AND_ENTER_DETAIL.ASSIST_ENTER.getValue());
            assistEnter.setWorkCenterCode(assistOutAndEnter.getAssistWorkCenterCode());
            assistEnter.setWorkCenterName(assistOutAndEnter.getAssistWorkCenterName());
            assistOutAndEnterList.add(assistEnter);
        }
        //影响时间/分钟=影响人数*（结束时间-开始时间）
        Double startTime = Double.valueOf(DateUtil.parse(assistOutAndEnter.getStartTime()).getTime());
        Double endTime = Double.valueOf(DateUtil.parse(assistOutAndEnter.getEndTime()).getTime());
        //assistOutAndEnter.setInfluenceTime(assistOutAndEnter.getInfluenceNumber() * ((endTime - startTime) / 1000 / 60));
        assistOutAndEnterList.add(assistOutAndEnter);
        for (MesAssistOutAndEnter mesAssistOutAndEnter : assistOutAndEnterList) {
            ConvertBean.serviceModelInitialize(mesAssistOutAndEnter, assistOutAndEnter.getCreateUser());
            mesAssistOutAndEnter.setInfluenceTime(assistOutAndEnter.getInfluenceNumber() * ((endTime - startTime) / 1000 / 60));
        }

        assistOutAndEnterRepository.saveAll(assistOutAndEnterList);
    }

    @Override
    public MesAssistOutAndEnter updateAssistOutAndEnter(MesAssistOutAndEnter assistOutAndEnter) {
        MesAssistOutAndEnter assistOutAndEnterDb = assistOutAndEnterRepository.getById(assistOutAndEnter.getId());
        if (assistOutAndEnterDb == null) {
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION_DATA_NOT_EXIT.getCode())
                    .setErrorDetail("ID[%s]记录不存在", assistOutAndEnter.getId())
                    .build();
        }
        //影响时间/分钟=影响人数*（结束时间-开始时间）
        Double startTime = Double.valueOf(DateUtil.parse(assistOutAndEnter.getStartTime()).getTime());
        Double endTime = Double.valueOf(DateUtil.parse(assistOutAndEnter.getEndTime()).getTime());
        assistOutAndEnter.setInfluenceTime(assistOutAndEnter.getInfluenceNumber() * ((endTime - startTime) / 1000 / 60));

        ConvertBean.serviceModelUpdate(assistOutAndEnter, assistOutAndEnter.getModifyUser());
        return assistOutAndEnterRepository.save(assistOutAndEnter);
    }

    @Override
    public int updateAssistOutAndEnterValidById(Long id, Integer status, String organizeCode, String userName) {
        if (status != CommonEnumUtil.IS_VAILD.INVAILD.getValue() && status != CommonEnumUtil.IS_VAILD.VAILD.getValue()) {
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                    .setErrorDetail("启用，禁用枚举状态值【%s】未被定义", status)
                    .build();
        }
        MesAssistOutAndEnter AssistOutAndEnterDb = assistOutAndEnterRepository.getById(id);
        if (AssistOutAndEnterDb == null || CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValue() == AssistOutAndEnterDb.getIsDeleted()) {
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION_DATA_NOT_EXIT.getCode())
                    .setErrorDetail("ID[%s]记录不存在", id)
                    .build();
        }
        return assistOutAndEnterRepository.updateByProperties(new String[]{MesExtConstWords.ID}, new Object[]{id},
                new String[]{MesExtConstWords.IS_VALID, MesExtConstWords.MODIFY_USER, MesExtConstWords.MODIFY_DATE_TIME},
                new Object[]{status, userName, TimeTool.getNowTime(true)});
    }

    @Override
    public int deleteAssistOutAndEnterId(Long id, String organizeCode, String userName) {
        //对id做有效性校验
        MesAssistOutAndEnter AssistOutAndEnterDb = assistOutAndEnterRepository.getById(id);
        if (AssistOutAndEnterDb == null || CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValue() == AssistOutAndEnterDb.getIsDeleted()) {
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION_DATA_NOT_EXIT.getCode())
                    .setErrorDetail("ID[%s]记录不存在", id)
                    .build();
        }

        return assistOutAndEnterRepository.updateByProperties(new String[]{MesExtConstWords.ID}, new Object[]{id},
                new String[]{MesExtConstWords.IS_DELETED, MesExtConstWords.MODIFY_USER, MesExtConstWords.MODIFY_DATE_TIME},
                new Object[]{CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValue(), userName, TimeTool.getNowTime(true)});
    }

    @Override
    public List<MesAssistOutAndEnterDateSumModel> queryAssistOutAndEnterDateSum(MesAssistOutAndEnterDateSumModel model) {
        List<MesAssistOutAndEnterDateSumModel> resultList = null;
        List<MesAssistOutAndEnterDateSumModel> modelList = assistOutAndEnterDao.queryAssistOutAndEnter(model);
        DecimalFormat obj = new DecimalFormat("0.##");
        if (CollectionUtils.isEmpty(modelList)) {
            log.info("援入援出时间汇总报表未查询到数据,维度[{}][{}]",
                    MesExtEnumUtil.REPORT_DIMENSION_DATE.valueOfDescription(model.getDimension()), MesExtEnumUtil.REPORT_DIMENSION_UN_WORK_TIME_STATISTICS.valueOfDescription(model.getDimension1()));
            return resultList;
        }
        log.info("援入援出时间汇总报表已查询到数据,维度[{}][{}]",
                MesExtEnumUtil.REPORT_DIMENSION_DATE.valueOfDescription(model.getDimension()), MesExtEnumUtil.REPORT_DIMENSION_UN_WORK_TIME_STATISTICS.valueOfDescription(model.getDimension1()));
        packUnWorkTimeStatisticsWorkTime(modelList, model);

        Map<String, List<MesAssistOutAndEnterDateSumModel>> modelMap = packUnWorkTimeStatisticsMap(modelList, model.getDimension1());
        if (CollectionUtils.isEmpty(modelMap)) {
            return resultList;
        }
        log.info("援入援出时间汇总报表根据维度封装数据成功,维度[{}][{}]",
                MesExtEnumUtil.REPORT_DIMENSION_DATE.valueOfDescription(model.getDimension()), MesExtEnumUtil.REPORT_DIMENSION_UN_WORK_TIME_STATISTICS.valueOfDescription(model.getDimension1()));
        for (String key : modelMap.keySet()) {
            if (StringUtils.isEmpty(key)) {
                continue;
            }
            List<MesAssistOutAndEnterDateSumModel> itemList = modelMap.get(key);
            if (CollectionUtils.isEmpty(itemList)) {
                continue;
            }
            String[] keyArr = key.split(MesExtConstWords.AND);

            MesAssistOutAndEnterDateSumModel result = new MesAssistOutAndEnterDateSumModel();
            packWorkTimeStatisticsResult(result, keyArr, model.getDimension1(), itemList.get(0));
            Double assistEnter = itemList.stream().filter(k -> k.getAssistOutAndEnterDetail() == MesExtEnumUtil.ASSIST_OUT_AND_ENTER_DETAIL.ASSIST_ENTER.getValue()).mapToDouble(k -> k.getInfluenceTime()).sum();
            Double inAssistOut = itemList.stream().filter(k -> k.getAssistOutAndEnterDetail() == MesExtEnumUtil.ASSIST_OUT_AND_ENTER_DETAIL.IN_ASSIST_OUT.getValue()).mapToDouble(k -> k.getInfluenceTime()).sum();
            Double newcomerAssistOut = itemList.stream().filter(k -> k.getAssistOutAndEnterDetail() == MesExtEnumUtil.ASSIST_OUT_AND_ENTER_DETAIL.NEWCOMER_ASSIST_OUT.getValue()).mapToDouble(k -> k.getInfluenceTime()).sum();
            Double externalAssistOut = itemList.stream().filter(k -> k.getAssistOutAndEnterDetail() == MesExtEnumUtil.ASSIST_OUT_AND_ENTER_DETAIL.EXTERNAL_ASSIST_OUT.getValue()).mapToDouble(k -> k.getInfluenceTime()).sum();
            Double makeAssistOut = itemList.stream().filter(k -> k.getAssistOutAndEnterDetail() == MesExtEnumUtil.ASSIST_OUT_AND_ENTER_DETAIL.MAKE_ASSIST_OUT.getValue()).mapToDouble(k -> k.getInfluenceTime()).sum();

            result.setAssistEnter(assistEnter);
            result.setInAssistOut(inAssistOut);
            result.setNewcomerAssistOut(newcomerAssistOut);
            result.setExternalAssistOut(externalAssistOut);
            result.setMakeAssistOut(makeAssistOut);

            result.setAssistEnterStr(obj.format(assistEnter));
            result.setInAssistOutStr(obj.format(inAssistOut));
            result.setNewcomerAssistOutStr(obj.format(newcomerAssistOut));
            result.setExternalAssistOutStr(obj.format(externalAssistOut));
            result.setMakeAssistOutStr(obj.format(makeAssistOut));

            result.setCountAssistOut(inAssistOut + newcomerAssistOut + externalAssistOut + makeAssistOut);

            if (CollectionUtils.isEmpty(resultList)) {
                resultList = new ArrayList<>();
            }
            resultList.add(result);
        }
        log.info("援入援出时间汇总数据开始重新排序,维度[{}][{}]",
                MesExtEnumUtil.REPORT_DIMENSION_DATE.valueOfDescription(model.getDimension()), MesExtEnumUtil.REPORT_DIMENSION_UN_WORK_TIME_STATISTICS.valueOfDescription(model.getDimension1()));
        if (!CollectionUtils.isEmpty(resultList)) {
            resultList = sortWorkTimeStatisticsResult(resultList, model.getDimension1());
            log.info("援入援出时间汇总数据重新排序成功,维度[{}][{}]",
                    MesExtEnumUtil.REPORT_DIMENSION_DATE.valueOfDescription(model.getDimension()), MesExtEnumUtil.REPORT_DIMENSION_UN_WORK_TIME_STATISTICS.valueOfDescription(model.getDimension1()));
        }
        return resultList;
    }

    public List<MesAssistOutAndEnterDateSumModel> sortWorkTimeStatisticsResult(List<MesAssistOutAndEnterDateSumModel> resultList, Integer dimension) {
        switch (MesExtEnumUtil.REPORT_DIMENSION_UN_WORK_TIME_STATISTICS.getByValue(dimension)) {
            case DATE:
                resultList = resultList.stream().sorted(Comparator.comparing(MesAssistOutAndEnterDateSumModel::getInfluenceDate)).collect(Collectors.toList());
                break;
            case IS_DONT:
                resultList = resultList.stream().sorted(Comparator.comparing(MesAssistOutAndEnterDateSumModel::getInfluenceDate)
                        .thenComparing(MesAssistOutAndEnterDateSumModel::getIsDont)).collect(Collectors.toList());
                break;
            case DONT_CLASS:
                resultList = resultList.stream().sorted(Comparator.comparing(MesAssistOutAndEnterDateSumModel::getInfluenceDate)
                        .thenComparing(MesAssistOutAndEnterDateSumModel::getIsDont)
                        .thenComparing(MesAssistOutAndEnterDateSumModel::getDontClass)).collect(Collectors.toList());
                break;
            case CENTER:
                resultList = resultList.stream().sorted(Comparator.comparing(MesAssistOutAndEnterDateSumModel::getInfluenceDate)
                        .thenComparing(MesAssistOutAndEnterDateSumModel::getIsDont)
                        .thenComparing(MesAssistOutAndEnterDateSumModel::getDontClass)
                        .thenComparing(MesAssistOutAndEnterDateSumModel::getWorkCenterCode)).collect(Collectors.toList());
                break;
        }
        return resultList;
    }

    public void packWorkTimeStatisticsResult(MesAssistOutAndEnterDateSumModel result, String[] keyArr, Integer dimension, MesAssistOutAndEnterDateSumModel model) {
        result.setInfluenceDate(keyArr[0]);
        switch (MesExtEnumUtil.REPORT_DIMENSION_UN_WORK_TIME_STATISTICS.getByValue(dimension)) {
            case DATE:
                break;
            case IS_DONT:
                result.setIsDont(keyArr[1]);
                break;
            case DONT_CLASS:
                result.setIsDont(keyArr[1]);
                result.setDontClass(keyArr[2]);
                break;
            case CENTER:
                result.setIsDont(keyArr[1]);
                result.setDontClass(keyArr[2]);
                result.setWorkCenterCode(keyArr[3]);
                result.setWorkCenterName(model.getWorkCenterName());
                break;
        }
    }

    public Map<String, List<MesAssistOutAndEnterDateSumModel>> packUnWorkTimeStatisticsMap(List<MesAssistOutAndEnterDateSumModel> modelList, Integer dimension) {
        Map<String, List<MesAssistOutAndEnterDateSumModel>> modelMap;
        if (CollectionUtils.isEmpty(modelList)) {
            return null;
        }
        switch (MesExtEnumUtil.REPORT_DIMENSION_UN_WORK_TIME_STATISTICS.getByValue(dimension)) {
            case DATE:
                modelMap = modelList.stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getInfluenceDate())))
                        .collect(Collectors.groupingBy(MesAssistOutAndEnterDateSumModel::getInfluenceDate));
                break;
            case IS_DONT:
                modelMap = modelList.stream().filter(
                                o -> (null != o && !StringUtils.isEmpty(o.getInfluenceDate()) && !StringUtils.isEmpty(o.getIsDont())))
                        .collect(Collectors.groupingBy(o -> (new StringJoiner(MesExtConstWords.AND)
                                .add(o.getInfluenceDate()).add(o.getIsDont()).toString())));
                break;
            case DONT_CLASS:
                modelMap = modelList.stream().filter(
                                o -> (null != o && !StringUtils.isEmpty(o.getInfluenceDate()) && !StringUtils.isEmpty(o.getIsDont())
                                        && !StringUtils.isEmpty(o.getDontClass())))
                        .collect(Collectors.groupingBy(o -> (new StringJoiner(MesExtConstWords.AND)
                                .add(o.getInfluenceDate()).add(o.getIsDont()).add(o.getDontClass()).toString())));
                break;
            case CENTER:
            default:
                modelMap = modelList.stream().filter(
                                o -> (null != o && !StringUtils.isEmpty(o.getInfluenceDate()) && !StringUtils.isEmpty(o.getIsDont())
                                        && !StringUtils.isEmpty(o.getDontClass()) && !StringUtils.isEmpty(o.getWorkCenterCode())))
                        .collect(Collectors.groupingBy(o -> (new StringJoiner(MesExtConstWords.AND)
                                .add(o.getInfluenceDate()).add(o.getIsDont()).add(o.getDontClass()).add(o.getWorkCenterCode()).toString())));
                break;
        }
        return modelMap;
    }

    public void packUnWorkTimeStatisticsWorkTime(List<MesAssistOutAndEnterDateSumModel> modelList, MesAssistOutAndEnterDateSumModel model) {
        if (MesExtEnumUtil.REPORT_DIMENSION_DATE.ONE.getValue() == model.getDimension()) {
            List<MesAssistOutAndEnterDateSumModel> modelListOrder = modelList.stream()
                    .filter(o -> (null != o && !StringUtils.isEmpty(o.getInfluenceDate()))).sorted(Comparator.comparing(MesAssistOutAndEnterDateSumModel::getInfluenceDate)).collect(Collectors.toList());
            if (!CollectionUtils.isEmpty(modelListOrder)) {
                String workTime = new StringJoiner(MesExtConstWords.TO)
                        .add(!StringUtils.isEmpty(model.getInfluenceDateStart()) ? model.getInfluenceDateStart() : modelListOrder.get(0).getInfluenceDate())
                        .add(!StringUtils.isEmpty(model.getInfluenceDateEnd()) ? model.getInfluenceDateEnd() : modelListOrder.get(modelListOrder.size() - 1).getInfluenceDate()).toString();
                modelList.stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getInfluenceDate()))).forEach(o -> {
                    o.setInfluenceDate(workTime);
                });
            }
        } else if (MesExtEnumUtil.REPORT_DIMENSION_DATE.YEAR.getValue() == model.getDimension()) {
            modelList.stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getInfluenceDate()))).forEach(o -> {
                o.setInfluenceDate(o.getInfluenceDate().substring(0, 4));
            });
        } else if (MesExtEnumUtil.REPORT_DIMENSION_DATE.MONTH.getValue() == model.getDimension()) {
            modelList.stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getInfluenceDate()))).forEach(o -> {
                o.setInfluenceDate(o.getInfluenceDate().substring(0, 7));
            });
        }
    }

}
