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

import cn.estsh.i3plus.ext.mes.api.busi.IProjectBadRateService;
import cn.estsh.i3plus.ext.mes.api.busi.ep.IEpWorkCenterRunningStateService;
import cn.estsh.i3plus.ext.mes.pojo.bean.*;
import cn.estsh.i3plus.ext.mes.pojo.model.ep.EpWorkCenterStateModel;
import cn.estsh.i3plus.ext.mes.pojo.repository.*;
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.TimeTool;
import cn.estsh.i3plus.pojo.base.bean.DdlPackBean;
import cn.estsh.i3plus.pojo.base.tool.DdlPreparedPack;
import cn.estsh.i3plus.pojo.mes.bean.MesWorkCenter;
import cn.estsh.i3plus.pojo.mes.bean.MesWorkOrder;
import cn.estsh.i3plus.pojo.mes.repository.MesWorkOrderRepository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @PROJECT_NAME: i3plus-mes-panasonic
 * @DESCRIPTION:
 * @USER: xinwang.yi
 * @DATE: 2022-05-30 15:28
 */
@Slf4j
@Service
public class EpWorkCenterRunningStateService implements IEpWorkCenterRunningStateService {

    @Autowired
    private MesOutPutStatisticsRepository outPutStatisticsRDao;

    @Autowired
    private MesShiftProdCenterRecordRepository shiftProdCenterRecordDao;

    @Autowired
    private MesWorkOrderRepository workOrderDao;

    @Autowired
    private MesWorkOrderExtRepository workOrderExtDao;

    @Autowired
    private MesRepairTaskRepository repairTaskRDao;

    @Autowired
    private MesWorkCenterExtRepository workCenterExtRepository;

    @Autowired
    private MesBusiConfigRepository busiConfigRepository;

    @Autowired
    private IProjectBadRateService projectBadRateService;

    @Override
    public List<EpWorkCenterStateModel> getWorkCenterState(String organizeCode) {

        List<EpWorkCenterStateModel> result = new ArrayList<>();

        List<MesBusiConfig> busiConfigWorkCenterList = getBusiConfigWorkCenterList(organizeCode);
        //无配置 则跳过
        if (CollectionUtils.isEmpty(busiConfigWorkCenterList)){
            return result;
        }

        //工单作业时间
        //当前日期
        String today = TimeTool.getToday();

        //根据业务配置表中的产线代码 获取 产线信息
        List<MesWorkCenterExt> workCenterExtList = getWorkCenterExtByCode(organizeCode, busiConfigWorkCenterList.stream().map(MesBusiConfig::getCfgValue).collect(Collectors.toList()));
        Map<String, MesWorkCenterExt> workCenterMap = workCenterExtList.stream().collect(Collectors.toMap(MesWorkCenterExt::getWorkCenterCode, Function.identity()));

        List<String> workCenterCodes = workCenterExtList.stream().map(MesWorkCenter::getWorkCenterCode).collect(Collectors.toList());
        //当前系统时间去查询是存在停开机记录当中的数据
        Map<String, MesShiftProdCenterRecord> stringMesShiftProdCenterRecordMap = getShiftProdCenterRecordMap(organizeCode, workCenterCodes);

        for (MesBusiConfig busiConfig : busiConfigWorkCenterList) {
            EpWorkCenterStateModel epWorkCenterStateModel = new EpWorkCenterStateModel();
            if (!CollectionUtils.isEmpty(workCenterExtList)) {
                MesWorkCenterExt workCenterExtDb = CollectionUtils.isEmpty(workCenterMap) ? null : workCenterMap.get(busiConfig.getCfgValue());

                if(workCenterExtDb != null){

                    //产线名称
                    epWorkCenterStateModel.setWorkCenterName(workCenterExtDb.getWorkCenterDesc());

                    String workTime = workCenterExtDb.getWorkTime();
                    if (StringUtils.isEmpty(workTime)) {
                        workTime = today;
                    }

                    //查询当天所有的有效工单
                    Map<String, MesWorkOrderExt> workOrderMap = getWorkOrderMap(organizeCode, workCenterExtDb, workTime);

                    //通过产线查询当天计生产实绩
                    List<MesOutPutStatistics> outPutStatisticsList = getMesOutPutStatistics(organizeCode, workCenterExtDb, workTime);

                    List<String> workOrderNos =  CollectionUtils.isEmpty(outPutStatisticsList) ? null : outPutStatisticsList.stream().map(MesOutPutStatistics::getWorkOrderNo).collect(Collectors.toList());

                    //返修数据
                    List<MesRepairTask> repairTasks = CollectionUtils.isEmpty(workOrderNos) ? null : getMesRepairTasksByTodayAndWoNo(workOrderNos, organizeCode);

                    //当前生产或待生产的启动工单
                    MesWorkOrder mesWorkOrder = CollectionUtils.isEmpty(workOrderMap) || !workOrderMap.containsKey(workCenterExtDb.getWorkCenterCode()) ? null : workOrderMap.get(workCenterExtDb.getWorkCenterCode());

                    //获取当前产线停开机记录
                    MesShiftProdCenterRecord shiftProdCenterRecord = CollectionUtils.isEmpty(stringMesShiftProdCenterRecordMap) ? null : stringMesShiftProdCenterRecordMap.get(workCenterExtDb.getWorkCenterCode());

                    // 无启动工单
                    if((mesWorkOrder == null && CollectionUtils.isEmpty(outPutStatisticsList)) || (shiftProdCenterRecord == null)) {
                        continue;
                    }else{
                        //当日实际生产
                        Double sumCompleteQty = CollectionUtils.isEmpty(outPutStatisticsList) ? 0.00 : outPutStatisticsList.stream().map(MesOutPutStatistics::getQty).reduce(0.00, Double::sum);
                        Double repairQty = CollectionUtils.isEmpty(repairTasks) ? 0.00 : repairTasks.stream().map(MesRepairTask::getRepairQty).reduce(0.00, Double::sum);

                        //不良率 = 当日不良数量汇总/当日实绩汇总*100%，保留1位小数。
                        if (BigDecimal.valueOf(sumCompleteQty).compareTo(BigDecimal.ZERO) > 0) {
                            BigDecimal defectiveRate = BigDecimal.valueOf(repairQty).compareTo(BigDecimal.ZERO) > 0 ? BigDecimal.valueOf(repairQty).divide(BigDecimal.valueOf(sumCompleteQty), 3, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)) : BigDecimal.ZERO;
                            epWorkCenterStateModel.setDefectiveRate(defectiveRate.doubleValue() + "%");
                        } else {
                            epWorkCenterStateModel.setDefectiveRate(0.0 + "%");
                        }

                        //当前生产机种（物料名称）
                        if(mesWorkOrder == null){
                            epWorkCenterStateModel.setPartName(outPutStatisticsList.get(0).getPartNo());
                        }else{
                            epWorkCenterStateModel.setPartName(mesWorkOrder.getPartNo());
                        }
                        //通知栏：
                        //停机类型
                        Integer prodType = shiftProdCenterRecord.getProdType();
                        //判断存在于哪个停开机类型
                        switch (MesExtEnumUtil.SHIFT_PROD_TYPE.getByValue(prodType)) {
                            //红色 异常停机项目描述：停机作业记录中非常规停机项目描述。
                            case UNNORMAL_STOP_CENTER:
                                epWorkCenterStateModel.setWorkCenterStatus("red");
                                epWorkCenterStateModel.setWorkCenterStatusName("异常停机");
                                break;
                            case NORMAL_STOP_CENTER:
                                epWorkCenterStateModel.setWorkCenterStatus("red");
                                epWorkCenterStateModel.setWorkCenterStatusName("常规停机");
                                break;
                            case UNNORMAL_PROD:
                                epWorkCenterStateModel.setWorkCenterStatus("green");
                                epWorkCenterStateModel.setWorkCenterStatusName("加班生产");
                                break;
                            case NORMAL_PROD:
                                epWorkCenterStateModel.setWorkCenterStatus("green");
                                epWorkCenterStateModel.setWorkCenterStatusName("正常生产");
                                break;
                            default:
                                epWorkCenterStateModel.setWorkCenterStatus("red");
                                epWorkCenterStateModel.setWorkCenterStatusName("常规停机");
                                break;
                        }
                    }
                    result.add(epWorkCenterStateModel);
                }else {
                    log.info("getWorkCenterState-产线：{}不存在", busiConfig.getCfgValue());
                }
            }
        }

        return result;
    }

    private Map<String, MesShiftProdCenterRecord> getShiftProdCenterRecordMap(String organizeCode, List<String> workCenterCodes) {
        List<MesShiftProdCenterRecord> shiftProdCenterRecordByNowList = getShiftProdCenterRecordByNow(workCenterCodes, organizeCode);
        return CollectionUtils.isEmpty(shiftProdCenterRecordByNowList) ? null : shiftProdCenterRecordByNowList.stream().collect(
                Collectors.groupingBy(MesShiftProdCenterRecord::getWorkCenterCode, Collectors.collectingAndThen(Collectors.reducing((wo1, wo2) -> wo1.getModifyDatetime().compareTo(wo2.getModifyDatetime()) > 0 ? wo1 : wo2), Optional::get)));
    }

    private Map<String, MesWorkOrderExt> getWorkOrderMap(String organizeCode, MesWorkCenterExt centerExt, String workTime) {
        List<MesWorkOrderExt> workOrderExtList = projectBadRateService.getWorkOrderExtsContainReusePlanDatetime(centerExt.getWorkCenterCode(), workTime, organizeCode);

        return CollectionUtils.isEmpty(workOrderExtList) ? null : workOrderExtList.stream().collect(
                Collectors.groupingBy(MesWorkOrderExt::getWorkCenterCode, Collectors.collectingAndThen(Collectors.reducing(( wo1,wo2) -> wo1.getSeq().compareTo(wo2.getSeq()) < 0? wo1:wo2), Optional::get)));
    }

    private List<MesOutPutStatistics> getMesOutPutStatistics(String organizeCode, MesWorkCenterExt centerExt, String today) {
        DdlPackBean packBean = DdlPackBean.getDdlPackBean(organizeCode);
        DdlPreparedPack.getStringEqualPack(centerExt.getWorkCenterCode(), MesExtConstWords.WORK_CENTER_CODE, packBean);
        DdlPreparedPack.getStringEqualPack(today, MesExtConstWords.WORK_TIME, packBean);
        packBean.setOrderByStr(" order by modifyDatetime desc ");
        return outPutStatisticsRDao.findByHqlWhere(packBean);
    }

    private List<MesBusiConfig> getBusiConfigWorkCenterList(String organizeCode) {
        DdlPackBean packBean = DdlPackBean.getDdlPackBean(organizeCode);
        DdlPreparedPack.getStringEqualPack(MesExtConstWords.BOARD_WORK_SHOW_FLAG, MesExtConstWords.CFG_CODE, packBean);
        packBean.setOrderByStr(" order by cfgValueSeq asc ");
        return busiConfigRepository.findByHqlWhere(packBean);
    }

    private List<MesWorkCenterExt> getWorkCenterExtByCode(String organizeCode, List<String> workCenterCode) {
        DdlPackBean workCenterCondition = DdlPackBean.getDdlPackBean(organizeCode);
        DdlPreparedPack.getInPackList( workCenterCode, MesExtConstWords.WORK_CENTER_CODE, workCenterCondition);
        return workCenterExtRepository.findByHqlWhere(workCenterCondition);
    }

    private List<MesOutPutStatistics> getOutPutStatistics(List<String> workCenterCodes, String workTime, String shiftCode, String partNo, String organizeCode) {
        DdlPackBean outPutStatisticsPackBean = DdlPackBean.getDdlPackBean(organizeCode);
        DdlPreparedPack.getInPackList(workCenterCodes, "workCenterCode", outPutStatisticsPackBean);
        DdlPreparedPack.getStringEqualPack(workTime, "workTime", outPutStatisticsPackBean);
        if (!StringUtils.isEmpty(shiftCode)) {
            DdlPreparedPack.getStringEqualPack(shiftCode, "shiftCode", outPutStatisticsPackBean);
        }
        if (!StringUtils.isEmpty(partNo)) {
            DdlPreparedPack.getStringEqualPack(partNo, "partNo", outPutStatisticsPackBean);
        }
        List<MesOutPutStatistics> outPutStatisticsList = outPutStatisticsRDao.findByHqlWhere(outPutStatisticsPackBean);
        return outPutStatisticsList;
    }

    private List<MesWorkOrder> getWorkOrderExt(List<String> workCenterCode, String organizeCode){
        DdlPackBean packBean = DdlPackBean.getDdlPackBean(organizeCode);
        DdlPreparedPack.getInPackList(workCenterCode, MesExtConstWords.WORK_CENTER_CODE, packBean);
        DdlPreparedPack.getNumEqualPack(MesExtEnumUtil.WORK_ORDER_STATUS.OPEN.getValue(), MesExtConstWords.WORK_ORDER_STATUS, packBean);
        return workOrderDao.findByHqlWhere(packBean);
    }

    public List<MesWorkOrderExt> getWorkOrderExts(String workCenterCodes, String currentTime, String organizeCode) {
        DdlPackBean workOrderCondition = DdlPackBean.getDdlPackBean(organizeCode);
        DdlPreparedPack.getStringEqualPack(workCenterCodes, MesExtConstWords.WORK_CENTER_CODE, workOrderCondition);
        //工单状态
        List<Integer> workOrderStatusList = Stream.of(
                MesExtEnumUtil.WORK_ORDER_STATUS.OPEN.getValue()).collect(Collectors.toList());

        DdlPreparedPack.getInPackList(workOrderStatusList, MesExtConstWords.WORK_ORDER_STATUS, workOrderCondition);
        DdlPreparedPack.getStringRightLikerPack(currentTime, MesExtConstWords.START_TIME, workOrderCondition);
        return workOrderExtDao.findByHqlWhere(workOrderCondition);
    }

    public List<MesShiftProdCenterRecord> getShiftProdCenterRecordByNow(List<String> workCenterCodes, String organizeCode) {
        DdlPackBean condition = DdlPackBean.getDdlPackBean(organizeCode);
        DdlPreparedPack.getInPackList(workCenterCodes, MesExtConstWords.WORK_CENTER_CODE, condition);
        DdlPreparedPack.getTimeBetweenCol(TimeTool.getNowTime(true), MesExtConstWords.START_TIME, MesExtConstWords.END_TIME, condition, true);
        return shiftProdCenterRecordDao.findByHqlWhere(condition);
    }

    private List<MesRepairTask> getMesRepairTasksByTodayAndWoNo(List<String> outPutWoNoList, String organizeCode) {
        DdlPackBean repairTaskBean = DdlPackBean.getDdlPackBean(organizeCode);
        DdlPreparedPack.getStringRightLikerPack(TimeTool.getToday(), "repairDate", repairTaskBean);
        DdlPreparedPack.getInPackList(outPutWoNoList, MesExtConstWords.WORK_ORDER_NO, repairTaskBean);
        List<MesRepairTask> repairTasks = repairTaskRDao.findByHqlWhere(repairTaskBean);
        return repairTasks;
    }
}
