package cn.estsh.i3plus.ext.mes.pcn.apiservice.serviceimpl.job.ep;

import cn.estsh.i3plus.ext.mes.pcn.api.base.IWorkCenterExtService;
import cn.estsh.i3plus.ext.mes.pcn.api.job.ep.IEpPersonCheckOrderService;
import cn.estsh.i3plus.ext.mes.pcn.pojo.bean.*;
import cn.estsh.i3plus.ext.mes.pcn.pojo.repository.*;
import cn.estsh.i3plus.ext.mes.pcn.pojo.util.MesPcnExtConstWords;
import cn.estsh.i3plus.ext.mes.pcn.pojo.util.MesPcnExtEnumUtil;
import cn.estsh.i3plus.mes.pcn.api.iservice.busi.ISyncFuncService;
import cn.estsh.i3plus.platform.common.convert.ConvertBean;
import cn.estsh.i3plus.platform.common.tool.TimeTool;
import cn.estsh.i3plus.pojo.base.bean.BaseResultBean;
import cn.estsh.i3plus.pojo.base.bean.DdlPackBean;
import cn.estsh.i3plus.pojo.base.enumutil.CommonEnumUtil;
import cn.estsh.i3plus.pojo.base.tool.DdlPreparedPack;
import cn.estsh.i3plus.pojo.mes.model.GenSerialNoModel;
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.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @Author: wangjie
 * @CreateDate: 2019/8/23 1:16 PM
 * @Description: EP-上岗证点检单据定时任务
 **/
@Slf4j
@Service
public class EpPersonCheckOrderService implements IEpPersonCheckOrderService {

    @Autowired
    private MesProcessCellRepository processCellRepository;

    @Autowired
    private MesProcessCheckRepository processCheckRepository;

    @Autowired
    private MesPersonCheckDetailRepository personCheckDetailRepository;

    @Autowired
    private MesOrderRuleRepository orderRuleRepository;

    @Autowired
    private MesOrderJobRepository orderJobRepository;

    @Autowired
    private IWorkCenterExtService workCenterExtService;

    @Autowired
    private MesWorkOrderExtRepository workOrderExtRepository;

    @Autowired
    private ISyncFuncService syncFuncService;

    @Override
    public void doPersonCheckOrder(String organizeCode) {
        List<MesOrderRule> orderRuleDbList = getOrderRuleList(organizeCode);
        if (CollectionUtils.isEmpty(orderRuleDbList)) {
            log.info("Pcn处理上岗证点检单据生成JOB,未配置单据规则");
            return;
        }

        Map<String, List<MesOrderRule>> workCenterCodeMap = orderRuleDbList.stream()
                .filter(o -> (null != o && !StringUtils.isEmpty(o.getWorkCenterCode()) && !StringUtils.isEmpty(o.getProduceTime())))
                .collect(Collectors.groupingBy(MesOrderRule::getWorkCenterCode));
        log.info("Pcn处理上岗证点检单据生成JOB,生成包含以下生产线{}", CollectionUtils.isEmpty(workCenterCodeMap) ? null : workCenterCodeMap.keySet().toString());

        for (String workCenterCode : workCenterCodeMap.keySet()) {
            if (StringUtils.isEmpty(workCenterCode)) continue;

            List<MesOrderRule> orderRuleList = workCenterCodeMap.get(workCenterCode);
            if (CollectionUtils.isEmpty(orderRuleList)) continue;

            MesWorkOrderExt workOrderExt = getWorkOrderByStatus(organizeCode, workCenterCode);

            Map<String, List<MesProcessCell>> processCodeMap = getProcessCodeMapByCenter(organizeCode, workCenterCode);
            List<String> processCodeList = getProcessCodeList(processCodeMap);
            log.info("Pcn处理上岗证点检单据生成JOB,生产线[{}]配置的数据量processCodeMap[{}],processCodeList[{}]",
                    workCenterCode, CollectionUtils.isEmpty(processCodeMap) ? 0 : processCodeMap.size(), CollectionUtils.isEmpty(processCodeList) ? 0 : processCodeList.size());

            List<MesProcessCheck> processCheckList = getProcessCheckList(workOrderExt, processCodeList);

            for (MesOrderRule orderRule : orderRuleList) {
               if (null == orderRule) continue;

               String produceTime = orderRule.getProduceTime() + MesPcnExtConstWords.APPEND_SECONDS;

               if (TimeTool.stringParseToDate(TimeTool.getNowTime(MesPcnExtConstWords.TIME_FORMAT)).compareTo(TimeTool.stringParseToDate(produceTime)) >= 0) {

                   String shiftCode = getCurShiftCode(orderRule.getShiftCode(), organizeCode, workCenterCode);
                   if (StringUtils.isEmpty(shiftCode)) {
                       log.info("Pcn处理上岗证点检单据生成JOB,生产线[{}]上岗证点检单据存在生成时间[{}]的单据规则,但未配置班次或生产线未启动班次", workCenterCode, produceTime);
                       continue;
                   }

                   List<MesOrderJob> orderJobList = getOrderJobList(organizeCode, workCenterCode, shiftCode, produceTime);
                   if (!CollectionUtils.isEmpty(orderJobList)) continue;

                   if (null == workOrderExt) {
                       log.info("Pcn处理上岗证点检单据生成JOB,生产线[{}]还未生成时间[{}]班次[{}]的上岗证点检单据,但未查询到启动或下达的工单", workCenterCode, produceTime, shiftCode);
                       continue;
                   }

                   if (CollectionUtils.isEmpty(processCodeList)) {
                       log.info("Pcn处理上岗证点检单据生成JOB,生产线[{}]还未生成时间[{}]班次[{}]的上岗证点检单据,但未配置工位工序关系", workCenterCode, produceTime, shiftCode);
                       continue;
                   }

                   if (CollectionUtils.isEmpty(processCheckList)) {
                       log.info("Pcn处理上岗证点检单据生成JOB,生产线[{}]还未生成时间[{}]班次[{}]的上岗证点检单据,但根据生产线查询到顺序最小的一个[{}]状态的工单[{}]关联的物料编码[{}]与工序代码{}未配置工序点检项目信息",
                               workCenterCode, produceTime, shiftCode, MesPcnExtEnumUtil.WORK_ORDER_STATUS.valueOfDescription(workOrderExt.getWorkOrderStatus()), workOrderExt.getOrderNo(), workOrderExt.getPartNo(), processCodeList.toString());
                       continue;
                   }

                   log.info("Pcn处理上岗证点检单据生成JOB,生产线[{}]正在生成时间[{}]班次[{}]的上岗证点检单据", workCenterCode, produceTime, shiftCode);
                   String orderNo = getOrderNo(organizeCode);
                   if (StringUtils.isEmpty(orderNo)) {
                       log.info("Pcn处理上岗证点检单据生成JOB,生产线[{}]生成时间[{}]班次[{}]的上岗证点检单据时生成单据号失败", workCenterCode, produceTime, shiftCode);
                       continue;
                   }
                   insertPersonCheckOrder(organizeCode, workCenterCode, shiftCode, produceTime, orderNo, processCheckList, processCodeMap);
               }
            }
        }

    }

    private List<String> getProcessCodeList(Map<String, List<MesProcessCell>> processCodeMap) {
        return CollectionUtils.isEmpty(processCodeMap) ? null : new ArrayList<>(processCodeMap.keySet()).stream().filter(o -> !StringUtils.isEmpty(o)).distinct().collect(Collectors.toList());
    }

    private Map<String, List<MesProcessCell>> getProcessCodeMapByCenter(String organizeCode, String workCenterCode) {
        List<MesProcessCell> processCellList = processCellRepository.findByProperty(
                new String[]{MesPcnExtConstWords.ORGANIZE_CODE, MesPcnExtConstWords.IS_VALID, MesPcnExtConstWords.IS_DELETED, MesPcnExtConstWords.WORK_CENTER_CODE},
                new Object[]{organizeCode, CommonEnumUtil.IS_VAILD.VAILD.getValue(), CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), workCenterCode});
        return CollectionUtils.isEmpty(processCellList) ? null :
                processCellList.stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getProcessCode()))).collect(Collectors.groupingBy(MesProcessCell::getProcessCode));
    }

    private List<MesProcessCheck> getProcessCheckList(MesWorkOrderExt workOrderExt, List<String> processCodeList) {
        if (null == workOrderExt) return null;
        if (CollectionUtils.isEmpty(processCodeList)) return null;
        DdlPackBean packBean = DdlPackBean.getDdlPackBean(workOrderExt.getOrganizeCode());
        DdlPreparedPack.getStringEqualPack(workOrderExt.getPartNo(), MesPcnExtConstWords.PART_NO, packBean);
        DdlPreparedPack.getInPackList(processCodeList, MesPcnExtConstWords.PROCESS_CODE, packBean);
        return processCheckRepository.findByHqlWhere(packBean);
    }

    private List<MesOrderRule> getOrderRuleList(String organizeCode) {
        DdlPackBean packBean = DdlPackBean.getDdlPackBean(organizeCode);
        DdlPreparedPack.getNumEqualPack(MesPcnExtEnumUtil.MES_OR_TASK_TYPE.PREPARE_TASK.getValue(), MesPcnExtConstWords.TASK_TYPE, packBean);
        DdlPreparedPack.getNumEqualPack(MesPcnExtEnumUtil.MES_OR_ORDER_TYPE.PERSON_CHECK.getValue(), MesPcnExtConstWords.ORDER_TYPE, packBean);
        DdlPreparedPack.getNumEqualPack(MesPcnExtEnumUtil.MES_OR_CREATE_RULE.TIME_TO_CREATE.getValue(), MesPcnExtConstWords.CREATE_RULE, packBean);
        return orderRuleRepository.findByHqlWhere(packBean);
    }

    private List<MesOrderJob> getOrderJobList(String organizeCode, String workCenterCode, String shiftCode, String produceTime) {
        DdlPackBean packBean = DdlPackBean.getDdlPackBean(organizeCode);
        DdlPreparedPack.getNumEqualPack(MesPcnExtEnumUtil.MES_OR_TASK_TYPE.PREPARE_TASK.getValue(), MesPcnExtConstWords.TASK_TYPE, packBean);
        DdlPreparedPack.getNumEqualPack(MesPcnExtEnumUtil.MES_OR_ORDER_TYPE.PERSON_CHECK.getValue(), MesPcnExtConstWords.ORDER_TYPE, packBean);
        DdlPreparedPack.getNumEqualPack(MesPcnExtEnumUtil.HANDLER_METHOD.AUTOMATICALLY_CREATED.getValue(), MesPcnExtConstWords.HANDLER_METHOD, packBean);
        DdlPreparedPack.getStringEqualPack(workCenterCode, MesPcnExtConstWords.WORK_CENTER_CODE, packBean);
        DdlPreparedPack.getStringEqualPack(shiftCode, MesPcnExtConstWords.SHIFT_CODE, packBean);
        DdlPreparedPack.getStringEqualPack(TimeTool.getToday() + MesPcnExtConstWords.ONE_SPACE + produceTime, MesPcnExtConstWords.GENERATE_TIME, packBean);
        return orderJobRepository.findByHqlWhere(packBean);
    }

    private String getCurShiftCode(String shiftCode, String organizeCode, String workCenterCode) {
        if (StringUtils.isEmpty(shiftCode)) {
            MesWorkCenterExt workCenterExt = workCenterExtService.getWorkCenterExtByWorkCenterCode(organizeCode, workCenterCode);
            if (null != workCenterExt) {
                shiftCode = workCenterExt.getShiftCode();
            }
        }
        return shiftCode;
    }

    private MesWorkOrderExt getWorkOrderByStatus(String organizeCode, String workCenterCode) {
        MesWorkOrderExt workOrderExt = getWorkOrderByStatus(organizeCode, workCenterCode, MesPcnExtEnumUtil.WORK_ORDER_STATUS.OPEN.getValue());
        if (null == workOrderExt) {
            workOrderExt = getWorkOrderByStatus(organizeCode, workCenterCode, MesPcnExtEnumUtil.WORK_ORDER_STATUS.LANDED.getValue());
        }
        return workOrderExt;
    }

    private MesWorkOrderExt getWorkOrderByStatus(String organizeCode, String workCenterCode, Integer workOrderStatus) {
        DdlPackBean packBean = DdlPackBean.getDdlPackBean(organizeCode);
        DdlPreparedPack.getNumEqualPack(workOrderStatus, MesPcnExtConstWords.WORK_ORDER_STATUS, packBean);
        DdlPreparedPack.getStringEqualPack(workCenterCode, MesPcnExtConstWords.WORK_CENTER_CODE, packBean);
        DdlPreparedPack.getOrderByPack(new Object[]{CommonEnumUtil.ASC_OR_DESC.ASC.getValue()}, new String[]{MesPcnExtConstWords.SEQ}, packBean);
        return workOrderExtRepository.getByProperty(packBean);
    }

    private String getOrderNo(String organizeCode) {
        String orderNo = null;
        try {
            BaseResultBean oneCodeResult = syncFuncService.syncSerialNo(new GenSerialNoModel(MesPcnExtConstWords.ORDER_NO_RULE), null, organizeCode, 1);
            if (oneCodeResult != null && oneCodeResult.isSuccess()) {
                orderNo = oneCodeResult.getResultList().get(0).toString();
            }
        } catch (Exception e) {
        }
        return orderNo;
    }

    private void insertPersonCheckOrder(String organizeCode, String workCenterCode, String shiftCode, String produceTime, String orderNo, List<MesProcessCheck> processCheckList, Map<String, List<MesProcessCell>> processCodeMap) {
        MesOrderJob orderJob = new MesOrderJob();
        orderJob.setTaskType(MesPcnExtEnumUtil.MES_OR_TASK_TYPE.PREPARE_TASK.getValue());
        orderJob.setOrderType(MesPcnExtEnumUtil.MES_OR_ORDER_TYPE.PERSON_CHECK.getValue());
        orderJob.setHandlerMethod(MesPcnExtEnumUtil.HANDLER_METHOD.AUTOMATICALLY_CREATED.getValue());
        orderJob.setOrderNo(orderNo);
        orderJob.setWorkCenterCode(workCenterCode);
        orderJob.setOrderStatus(MesPcnExtEnumUtil.MES_ORJ_ORDER_STATUS.CREATE.getValue());
        orderJob.setOrderDate(TimeTool.getToday());
        orderJob.setWorkTime(orderJob.getOrderDate());
        orderJob.setGenerateTime(orderJob.getOrderDate() + MesPcnExtConstWords.ONE_SPACE + produceTime);
        orderJob.setShiftCode(shiftCode);
        orderJob.setOrganizeCode(organizeCode);
        ConvertBean.serviceModelInitialize(orderJob, MesPcnExtConstWords.JOB);
        orderJobRepository.insert(orderJob);

        for (MesProcessCheck processCheck : processCheckList) {
            MesPersonCheckDetail personCheckDetail = new MesPersonCheckDetail();
            BeanUtils.copyProperties(processCheck, personCheckDetail, MesPcnExtConstWords.ID);
            personCheckDetail.setOrderNo(orderNo);
            personCheckDetail.setWorkCenterCode(workCenterCode);
            List<MesProcessCell> processCellList = processCodeMap.get(processCheck.getProcessCode());
            if (!CollectionUtils.isEmpty(processCellList)) {
                personCheckDetail.setWorkCellCode(processCellList.get(0).getWorkCellCode());
                personCheckDetail.setProcessName(processCellList.get(0).getProcessName());
            }
            personCheckDetail.setShiftCode(shiftCode);
            personCheckDetail.setOrderStatus(MesPcnExtEnumUtil.MES_ORJ_ORDER_STATUS.CREATE.getValue());
            personCheckDetail.setOrderDate(TimeTool.getToday());
            personCheckDetail.setShiftGroupCheck(MesPcnExtEnumUtil.SHIFT_GROUP_CHECK.NO.getValue());
            personCheckDetail.setQualityCheck(MesPcnExtEnumUtil.QUALITY_CHECK.NO.getValue());
            ConvertBean.serviceModelInitialize(personCheckDetail, MesPcnExtConstWords.JOB);
            personCheckDetailRepository.insert(personCheckDetail);
        }
    }
}