package com.ximai.mes.pro.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ximai.common.constant.UserConstants;
import com.ximai.common.exception.ServiceException;
import com.ximai.common.utils.MessageUtils;
import com.ximai.common.utils.data.DataUtil;
import com.ximai.common.utils.data.DateUtils;
import com.ximai.common.utils.data.ExceptionUtil;
import com.ximai.common.utils.data.StringUtils;
import com.ximai.mes.cal.service.ICalPlanWorkunitService;
import com.ximai.mes.constant.ProStartWorkEnum;
import com.ximai.mes.constant.TaskWorkunitStatusEnum;
import com.ximai.mes.constant.WorkorderConst;
import com.ximai.mes.constant.WorkorderStatusEnum;
import com.ximai.mes.md.domain.MdItem;
import com.ximai.mes.md.domain.MdWorkstation;
import com.ximai.mes.md.mapper.MdWorkstationMapper;
import com.ximai.mes.md.service.IMdItemService;
import com.ximai.mes.md.service.IMdWorkstationService;
import com.ximai.mes.pro.domain.*;
import com.ximai.mes.pro.domain.proWorkOrder.ProWorkOrderProcess;
import com.ximai.mes.pro.domain.proWorkOrder.ProWorkOrderProcessItem;
import com.ximai.mes.pro.domain.proWorkOrder.ProWorkorder;
import com.ximai.mes.pro.domain.productionSolution.ProProductionSolution;
import com.ximai.mes.pro.domain.sap.SAPDtoFeedback;
import com.ximai.mes.pro.domain.task.ProTask;
import com.ximai.mes.pro.domain.task.ProTaskWorkunit;
import com.ximai.mes.pro.domain.vo.ProFeedbackSplitInfo;
import com.ximai.mes.pro.domain.vo.ProFeedbackVo;
import com.ximai.mes.pro.domain.vo.ProPackagePrintResult;
import com.ximai.mes.pro.domain.vo.feedbackTaskVo;
import com.ximai.mes.pro.domain.vo.task.FeedbackValidateSerialNoParams;
import com.ximai.mes.pro.mapper.*;
import com.ximai.mes.pro.mapper.proWorkOrder.ProWorkOrderProcessItemMapper;
import com.ximai.mes.pro.mapper.proWorkOrder.ProWorkorderMapper;
import com.ximai.mes.pro.mapper.productionSolution.ProProductionSolutionMapper;
import com.ximai.mes.pro.mapper.task.ProTaskMapper;
import com.ximai.mes.pro.mapper.task.ProTaskWorkunitMapper;
import com.ximai.mes.pro.service.IProFeedbackService;
import com.ximai.mes.pro.service.IProProductQrcodeRecordService;
import com.ximai.mes.pro.service.IProStartWorkService;
import com.ximai.mes.pro.service.proWorkOrder.IProWorkOrderProcessService;
import com.ximai.mes.pro.service.proWorkOrder.IProWorkorderService;
import com.ximai.mes.pro.service.task.IProTaskService;
import com.ximai.mes.pro.service.task.IProTaskWorkunitService;
import com.ximai.system.strategy.AutoCodeUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

/**
 * 生产报工记录Service业务层处理
 *
 * @date 2022-07-10
 */
@Slf4j
@Service
public class ProFeedbackServiceImpl implements IProFeedbackService {
    @Resource
    private ProFeedbackMapper proFeedbackMapper;


    @Autowired
    private IProFeedbackService proFeedbackService;
    @Resource
    private ProProcessMapper proProcessMapper;
    @Autowired
    private ProWorkorderMapper proWorkorderMapper;
    @Autowired
    private ProTaskMapper proTaskMapper;
    @Autowired
    private IProTaskService proTaskService;
    @Autowired
    private IProProductQrcodeRecordService productQrcodeRecordService;
    @Autowired
    private IProTaskWorkunitService proTaskWorkunitService;
    @Autowired
    private ProArrangeMapper proArrangeMapper;

    @Autowired
    ProProductionSolutionMapper proProductionSolutionMapper;

    @Autowired
    private IProWorkorderService proWorkorderService;

    @Autowired
    private IMdWorkstationService mdWorkstationService;
    @Resource
    private ProWorkOrderProcessItemMapper proWorkOrderProcessItemMapper;

    @Autowired
    private IProWorkOrderProcessService proWorkOrderProcessService;
    @Autowired
    private IMdItemService mdItemService;
    @Autowired
    private IProStartWorkService proStartWorkService;
    @Resource
    private ProStartWorkMapper proStartWorkMapper;
    @Resource
    private ProTaskWorkunitMapper proTaskWorkunitMapper;
    @Autowired
    private ICalPlanWorkunitService planWorkunitService;
    @Resource
    private ProRecoilMaterialMapper proRecoilMaterialMapper;

    @Autowired
    private AutoCodeUtil autoCodeUtil;

    // 判断工单分割报工
    private static Double splitFeedBack(Double execSize, Map<Long, List<ProFeedback>> feedbackGroupMap, ProWorkorder proWorkorder, BigDecimal reportSize, ProFeedback feedback, Long itemSecond, BigDecimal qualifySize, BigDecimal unQualifySize, List<ProFeedback> tempFeedback, LinkedHashMap<String, ProFeedbackSplitInfo> feedbackWorkorder) {

        List<ProFeedback> feedbackList = feedbackGroupMap.get(proWorkorder.getWorkorderId());
        feedbackList = CollectionUtil.isEmpty(feedbackList) ? new ArrayList<>() : feedbackList;
        BigDecimal total = feedbackList.stream().map(ProFeedback::getQuantityFeedback).reduce(BigDecimal.ZERO, BigDecimal::add);

        // 工单数量 - 已报工数量 = 可报工数量
        BigDecimal quantity = proWorkorder.getQuantity();
        if (quantity.doubleValue() == total.doubleValue()) {
            return reportSize.doubleValue();
        }

        Double v = quantity.doubleValue() - total.doubleValue();
        // 10 - 100 = -90
        //  剩余数量
        double v2 = 0;
        if (execSize > 0) {
            // 第N次进入 可报工数量剩余数量
            v2 = v - execSize;
        } else {
            // 第一次进入可报工数量减去需要报工数量
            v2 = v - reportSize.doubleValue();
        }

        ProFeedback o = feedback.deepCopyObj();
        o.setWorkorderId(proWorkorder.getWorkorderId());
        o.setWorkorderCode(proWorkorder.getWorkorderCode());
        o.setWorkorderName(proWorkorder.getWorkorderName());
        o.setItemId(proWorkorder.getProductId());
        o.setItemCode(proWorkorder.getProductCode());
        o.setItemName(proWorkorder.getProductName());
        o.setQuantity(proWorkorder.getQuantity());
        ProFeedbackSplitInfo proFeedbackSplitInfo = new ProFeedbackSplitInfo();

        // 数量够扣
        if (v2 > 0 || v2 == 0) {

            BigDecimal feedBackSize = BigDecimal.valueOf(reportSize.doubleValue());
            if (v2 > 0 && execSize > 0) {
                feedBackSize = new BigDecimal(execSize);
            }

            // 将剩余的可以扣除商量保存
            if (qualifySize.doubleValue() > 0) {
                qualifySize = new BigDecimal(feedBackSize.toString());
            }

            if (unQualifySize.doubleValue() > 0) {
                unQualifySize = new BigDecimal(feedBackSize.toString());
            }

            o.setQuantityFeedback(feedBackSize);
            o.setQuantityQualify(qualifySize);
            o.setQuantityUnqualify(unQualifySize);
            proFeedbackSplitInfo = new ProFeedbackSplitInfo();
            proFeedbackSplitInfo.setQuantityQualify(qualifySize);
            proFeedbackSplitInfo.setQuantityUnqualify(unQualifySize);
            o.setAttr1("工用时" + itemSecond * o.getQuantityFeedback().longValue() + "秒");

            // 可报工数量大于报工数量则生成并将
            execSize = 0D;
        } else {
            double abs = Math.abs(v2);
            // 将多出来的 -90 下次全局循环
            BigDecimal subtract = reportSize.subtract(new BigDecimal(abs));
            o.setQuantityFeedback(subtract);
            proFeedbackSplitInfo = new ProFeedbackSplitInfo();
            if (qualifySize.doubleValue() > 0) {
                qualifySize = subtract;
            }

            if (unQualifySize.doubleValue() > 0) {
                unQualifySize = subtract;
            }

            proFeedbackSplitInfo.setQuantityQualify(qualifySize);
            o.setQuantityQualify(qualifySize);
            proFeedbackSplitInfo.setQuantityUnqualify(unQualifySize);
            o.setAttr1("工用时" + itemSecond * o.getQuantityFeedback().longValue() + "秒");
            execSize = abs;
        }

        proFeedbackSplitInfo.setWorkorder(proWorkorder);
        tempFeedback.add(o);
        proFeedbackSplitInfo.setFeedbackList(tempFeedback);
        feedbackWorkorder.put(proWorkorder.getWorkorderCode(), proFeedbackSplitInfo);

        feedbackList.add(o);
        feedbackGroupMap.put(proWorkorder.getWorkorderId(), feedbackList);
        return execSize;
    }

    // 比例分配
    private static void feedbackPercentageSplit(List<ProArrange> arrList, ProFeedback mainFeedBack, Double quantityFeedback, List<ProFeedback> splitFeedbackWorkorderList, LinkedHashMap<String, ProFeedbackSplitInfo> feedbackWorkorderMap, long itemSecond) {
        int count = 0;
        BigDecimal feedbackConst = new BigDecimal(quantityFeedback);
        for (ProArrange proArrange : arrList) {
            count++;
            ProWorkorder proWorkorder = proArrange.getProWorkorder();

            //  按照编排单顺序， 优先扣减顺序靠前的工单
            //  拿到工单数量
            //  判断当前工单的报工记录是否已经等于工单数量
            //  满足则跳过,没满足继续扣数

            if (proWorkorder == null) {
                continue;
            }

            ProFeedback deepCopyFeedbackVal = proWorkorder.deepSetObj(mainFeedBack);
            deepCopyFeedbackVal.setItemId(proWorkorder.getProductId());
            deepCopyFeedbackVal.setItemCode(proWorkorder.getProductCode());
            deepCopyFeedbackVal.setItemName(proWorkorder.getProductName());


            // 按工单报工
            BigDecimal multiply = feedbackConst.multiply(BigDecimal.valueOf(DataUtil.getNormalData(proWorkorder.getProcessingRatio())));
            BigDecimal val1 = BigDecimal.ZERO;
            if (count == arrList.size()) {
                if (CollectionUtil.isNotEmpty(splitFeedbackWorkorderList)) {
                    LongSummaryStatistics notLastFeedbackSize = splitFeedbackWorkorderList.stream().collect(Collectors.summarizingLong(x -> x.getQuantityFeedback().longValue()));
                    val1 = feedbackConst.subtract(new BigDecimal(notLastFeedbackSize.getSum())).setScale(0, RoundingMode.DOWN);
                }
            } else {
                if (multiply.doubleValue() >= 1) {
                    val1 = multiply.setScale(0, RoundingMode.DOWN);
                } else {
                    continue;
                }
            }

            deepCopyFeedbackVal.setQuantityFeedback(val1);
            deepCopyFeedbackVal.setQuantityQualify(val1);
            deepCopyFeedbackVal.setAttr1("工用时" + itemSecond * val1.doubleValue() + "秒");
            splitFeedbackWorkorderList.add(deepCopyFeedbackVal);
            feedbackWorkorderMap.put(proWorkorder.getWorkorderCode(), new ProFeedbackSplitInfo(val1, proWorkorder));
        }
    }

    /**
     * 查询生产报工记录
     *
     * @param recordId 生产报工记录主键
     * @return 生产报工记录
     */
    @Override
    public ProFeedback selectProFeedbackByRecordId(Long recordId) {
        ProFeedback proFeedback = proFeedbackMapper.selectProFeedbackByRecordId(recordId);
        proFeedback.setMachineTime(DataUtil.getNormalData(proFeedback.getMachineTime(), Double.class) * 60 + "");
        return proFeedback;
    }

    /**
     * 查询生产报工记录列表
     *
     * @param proFeedback 生产报工记录
     * @return 生产报工记录
     */
    @Override
    public List<ProFeedback> selectProFeedbackList(ProFeedback proFeedback) {
        return proFeedbackMapper.selectProFeedbackList(proFeedback);
    }

    @Override
    public List<ProFeedbackVo> queryProFeedbackListJoinTaskWorkUnit(QueryWrapper<ProFeedback> query) {
        return proFeedbackMapper.queryProFeedbackListJoinTaskWorkUnit(query);
    }

    /**
     * 查询生产报工记录列表
     *
     * @param query 生产报工记录
     * @return 生产报工记录
     */
    @Override
    public List<ProFeedback> selectProFeedbackList(QueryWrapper<ProFeedback> query) {
        return proFeedbackMapper.selectListByQw(query);
    }

    @Override
    public void validateSerialNo(FeedbackValidateSerialNoParams validateSerialNoParams) {
        QueryWrapper<ProWorkorder> query = new QueryWrapper<>();
        query.eq("t4.task_workunit_id", validateSerialNoParams.getTaskWorkunitId());
        List<ProWorkorder> listOrder = proWorkorderMapper.selectJoinTaskWorkunitByQw(query);
        ProWorkorder proWorkorder = listOrder.get(0);
        QueryWrapper<ProProductQrcodeRecord> proProductQrcodeRecordQuery = new QueryWrapper<>();
        proProductQrcodeRecordQuery.eq("qrcode", validateSerialNoParams.getQrcode());
        proProductQrcodeRecordQuery.eq("work_order_id", proWorkorder.getWorkorderId());
        //验证序列号是否属于该工单
        List<ProProductQrcodeRecord> qrcodeList = productQrcodeRecordService.selectProProductQrcodeRecordList(proProductQrcodeRecordQuery);
        if(qrcodeList.size()==0){
            throw new ServiceException(MessageUtils.message("pro.feedback.error.serialNo.not.bind.workOrder"));
        }
        //验证是否报工
        QueryWrapper<ProFeedback> feedbackQuery = new QueryWrapper<>();
        feedbackQuery.eq("qrcode", validateSerialNoParams.getQrcode());
        feedbackQuery.eq("task_workunit_id",validateSerialNoParams.getTaskWorkunitId());
        List<ProFeedback> feedbackList = proFeedbackService.selectProFeedbackList(feedbackQuery);
        if(feedbackList.size()>0){
            throw new ServiceException(MessageUtils.message("pro.feedback.error.repeat.serialNo.report"));
        }
    }

    /**
     * 新增生产报工记录
     *
     * @param proFeedback 生产报工记录
     * @return 结果
     */
    @Override
    public int insertProFeedback(ProFeedback proFeedback) {
        proFeedback.createAction();
        proFeedback.setFeedbackCode(autoCodeUtil.genSerialCode(UserConstants.FEEDBACK_CODE, ""));
        return proFeedbackMapper.insertProFeedback(proFeedback);
    }

    /**
     * 修改生产报工记录
     *
     * @param proFeedback 生产报工记录
     * @return 结果
     */
    @Override
    public int updateProFeedback(ProFeedback proFeedback) {
        proFeedback.updateAction();
        return proFeedbackMapper.updateProFeedback(proFeedback);
    }

    /**
     * 批量删除生产报工记录
     *
     * @param recordIds 需要删除的生产报工记录主键
     * @return 结果
     */
    @Override
    public int deleteProFeedbackByRecordIds(Long[] recordIds) {
        List<ProFeedback> proFeedbacks = proFeedbackMapper.selectListByQw(new QueryWrapper<ProFeedback>().in("record_id", Arrays.asList(recordIds)));
        for (ProFeedback proFeedback : proFeedbacks) {
            BigDecimal quantityFeedback = proFeedback.getQuantityFeedback();

            ProTask proTask = proTaskService.selectProTaskByTaskId(proFeedback.getTaskId());
            ExceptionUtil.checkTrueThrowException(proTask.getIsLastProcess() == 1, MessageUtils.message("pro.feedback.error.cannot.delete.last.process"));

            proTask.setQuantityWait(proTask.getQuantityWait().add(proFeedback.getQuantityFeedback()));
            proTask.setQuantityUnqualify(proTask.getQuantityUnqualify().subtract(proFeedback.getQuantityUnqualify()));
            proTask.setQuantityQualify(proTask.getQuantityQualify().subtract(proFeedback.getQuantityQualify()));
            proTask.setQuantityProduced(proTask.getQuantityProduced().subtract(proFeedback.getQuantityFeedback()));
            proTaskService.updateProTask(proTask);

            ProTaskWorkunit proTaskWorkunit = proTaskWorkunitService.selectProTaskWorkunitByTaskWorkunitId(proFeedback.getTaskWorkunitId());
            proTaskWorkunit.setQuantityUnqualify(proTaskWorkunit.getQuantityUnqualify().subtract(proFeedback.getQuantityUnqualify()));
            proTaskWorkunit.setQuantityQualify(proTaskWorkunit.getQuantityQualify().subtract(proFeedback.getQuantityQualify()));
            proTaskWorkunit.setQuantityProduced(proTaskWorkunit.getQuantityProduced().subtract(proFeedback.getQuantityFeedback()));
            if (proTaskWorkunit.getQuantityProduced().doubleValue() < proTaskWorkunit.getQuantity().doubleValue()) {
                proTaskWorkunit.setStatus(TaskWorkunitStatusEnum.BEGINNING.getStatus());
                proTask.setTaskWorkunitId(proTaskWorkunit.getTaskWorkunitId());
                proTask.setWorkunitId(proTaskWorkunit.getWorkunitId());
                createStarkWorkRecord(proTask);
            }

            proTaskWorkunitService.updateProTaskWorkunit(proTaskWorkunit);
            ProTask nextProTask = proTaskService.getNextTaskByTaskId(proFeedback.getTaskId());
            if (nextProTask != null) {
                BigDecimal subtract = nextProTask.getQuantityWait().subtract(quantityFeedback);
                ExceptionUtil.checkTrueThrowException(subtract.doubleValue() < 0, MessageUtils.message("pro.feedback.error.error1"));
                nextProTask.setQuantityWait(subtract);
                proTaskService.updateProTask(nextProTask);
            }
        }
        return proFeedbackMapper.deleteProFeedbackByRecordIds(recordIds);
    }

    /**
     * 删除生产报工记录信息
     *
     * @param recordId 生产报工记录主键
     * @return 结果
     */
    @Override
    public int deleteProFeedbackByRecordId(Long recordId) {
        return proFeedbackMapper.deleteProFeedbackByRecordId(recordId);
    }

    private Double feedbackArrangeSortSplit(List<ProArrange> proArrangeList, ProFeedback mainFeedBack, Double waitQuantity, List<ProFeedback> splitFeedbackWorkorderList, LinkedHashMap<String, ProFeedbackSplitInfo> feedbackWorkorderMap, BigDecimal qualifySize, long itemSecond) {

        for (ProArrange proArrange : proArrangeList) {
            ProWorkorder proWorkorder = proArrange.getProWorkorder();

            //  按照编排单顺序， 优先扣减顺序靠前的工单
            //  拿到工单数量
            //  判断当前工单的报工记录是否已经等于工单数量
            //  满足则跳过,没满足继续扣数
            if (waitQuantity == 0) {
                return waitQuantity;
            }

            if (proWorkorder == null) {
                continue;
            }


            double feedBackedQuantity = proFeedbackService.selectQuantityQualifySum(new ProFeedback(null, proWorkorder.getWorkorderId(), null, mainFeedBack.getTaskWorkunitId()));
            double woQuantity = proWorkorder.getQuantity().doubleValue();
            if (feedBackedQuantity >= woQuantity) {
                continue;
            }

            ProFeedback deepFeedback = proWorkorder.deepSetObj(mainFeedBack);
            deepFeedback.setItemId(proWorkorder.getProductId());
            deepFeedback.setItemCode(proWorkorder.getProductCode());
            deepFeedback.setItemName(proWorkorder.getProductName());

            // 可 报工数量
            double quantityFeedbackVal = 0D;
            if (feedBackedQuantity == 0) {
                //  总数量 10 > 报工数量 7 = 3 else  总数量 7 > 报工数量 10 = -3
                quantityFeedbackVal = woQuantity > waitQuantity ? waitQuantity : woQuantity;
            } else {
                if (woQuantity > (waitQuantity + feedBackedQuantity)) {
                    quantityFeedbackVal = waitQuantity;
                } else {
                    double woWaitQuantity = woQuantity - feedBackedQuantity;
                    quantityFeedbackVal = Math.min(feedBackedQuantity, woWaitQuantity);
                }
            }

            waitQuantity = waitQuantity - quantityFeedbackVal;
            BigDecimal canFeedbackQuantity = BigDecimal.valueOf(quantityFeedbackVal);
            deepFeedback.setQuantityFeedback(canFeedbackQuantity);

            if (qualifySize.doubleValue() > 0) {
                deepFeedback.setQuantityQualify(canFeedbackQuantity);
                deepFeedback.setQuantityUnqualify(BigDecimal.ZERO);
                qualifySize = canFeedbackQuantity;
            }
            deepFeedback.setAttr1("工用时" + itemSecond * quantityFeedbackVal + "秒");
            splitFeedbackWorkorderList.add(deepFeedback);

            feedbackWorkorderMap.put(proWorkorder.getWorkorderCode(), new ProFeedbackSplitInfo(qualifySize, proWorkorder));
        }
        return waitQuantity;
    }

    @Transactional
    @Override
    public LinkedHashMap<String, ProFeedbackSplitInfo> taskFeedback(ProTask proTask, ProFeedback mainFeedBackVal) {

        //可分配合格数量
        BigDecimal quantityFeedback = DataUtil.getNormalData(mainFeedBackVal.getQuantityQualify());
        BigDecimal qualifySize = DataUtil.getNormalData(mainFeedBackVal.getQuantityQualify());
        BigDecimal unQualifySize = DataUtil.getNormalData(mainFeedBackVal.getQuantityUnqualify());
        Date normalDate = DataUtil.getNormalData(mainFeedBackVal.getStartTime());

        mainFeedBackVal.setQuantityUnqualify(unQualifySize);
        mainFeedBackVal.setTaskCode(proTask.getTaskCode());

        long diffInSecond = (DateUtils.getNowDate().getTime() - normalDate.getTime()) / (1000);
        long itemSecond = diffInSecond / quantityFeedback.longValue();

        String arrangeCode = proTask.getArrangeCode();
        QueryWrapper<ProWorkorder> wrapper = new QueryWrapper<>();
        wrapper.eq("t1.workorder_code", arrangeCode);
        wrapper.notIn("t1.status", Arrays.asList(WorkorderStatusEnum.CLOSE.getValue(), WorkorderStatusEnum.CANCEL.getValue(), WorkorderStatusEnum.CANCELED.getValue()));
        List<ProWorkorder> sourceWorkorders = proWorkorderMapper.selectListByQw(wrapper);

        LinkedHashMap<String, ProFeedbackSplitInfo> feedbackWorkorderMap = new LinkedHashMap<>();
        List<ProFeedback> splitFeedbackWorkorderList = new ArrayList<>();
        Long workorderId = mainFeedBackVal.getWorkorderId();
        String workorderCode = mainFeedBackVal.getWorkorderCode();

        double feedbackQuantityDouble = quantityFeedback.doubleValue();
        //  工序任务扣减报工数量
        //  如果报工数量大于工序任务待加工数量 则报错，
        //  否则将待加工数量扣掉
        //  将报工数量设置在报工记录当中

        Optional<ProWorkorder> first = sourceWorkorders.stream().filter(x -> Objects.equals(x.getWorkorderCode(), workorderCode)).findAny();
        ExceptionUtil.checkTrueThrowException(!first.isPresent(), MessageUtils.message("pro.workOrder.error.not.exist"));
        ProWorkorder workorder = first.get();
        mainFeedBackVal = workorder.deepSetObj(mainFeedBackVal);

        //按工单报工
        mainFeedBackVal.setItemId(workorder.getProductId());
        mainFeedBackVal.setItemCode(workorder.getProductCode());
        mainFeedBackVal.setItemName(workorder.getProductName());
        mainFeedBackVal.setQuantityFeedback(quantityFeedback);
        mainFeedBackVal.setQuantityQualify(qualifySize);
        mainFeedBackVal.setQuantityUnqualify(unQualifySize);
        mainFeedBackVal.setAttr1("工用时" + itemSecond * quantityFeedback.longValue() + "秒");

        ProFeedbackSplitInfo feedbackSplitInfo = new ProFeedbackSplitInfo();
        feedbackSplitInfo.setQuantityQualify(qualifySize);
        feedbackSplitInfo.setQuantityUnqualify(unQualifySize);
        feedbackSplitInfo.setWorkorder(workorder);
        splitFeedbackWorkorderList.add(mainFeedBackVal);
        feedbackWorkorderMap.put(workorder.getWorkorderCode(), feedbackSplitInfo);


        BigDecimal machineTime = BigDecimal.ZERO;
        BigDecimal breakTime = BigDecimal.ZERO;
        Map<String, Object> feedBackTimeMap = new HashMap<>();
        if (CollectionUtil.isNotEmpty(splitFeedbackWorkorderList)) {
            feedBackTimeMap = getFeedBackTimeMap(mainFeedBackVal);
            machineTime = DataUtil.getNormalData(feedBackTimeMap.get("machineTimeSecond"), BigDecimal.class);
            breakTime = DataUtil.getNormalData(feedBackTimeMap.get("breakTimeSecond"), BigDecimal.class);
        }

        for (ProFeedback proFeedback : splitFeedbackWorkorderList) {
            double v = proFeedback.getQuantityFeedback().doubleValue() / feedbackQuantityDouble;
            double mtimeSecond = machineTime.doubleValue() * v;
            double btimeSecond = breakTime.doubleValue() * v;
            double mtimeMin = mtimeSecond / 60;
            double btimeMin = btimeSecond / 60;
            feedBackTimeMap.put("mtimeSecond", mtimeSecond);
            feedBackTimeMap.put("btimeSecond", btimeSecond);
            // 发送报工
            proFeedback.setMachineTime(DataUtil.getNormalData(mtimeMin, "0"));
            proFeedback.setBreakTime(DataUtil.getNormalData(btimeMin, "0"));
            // 保存数据
            proFeedback.setCreateTime(new Date());
            this.insertProFeedback(proFeedback);
        }

        return feedbackWorkorderMap;
    }

    private void feedbackUnQuantitySplit(List<ProFeedback> splitFeedbackWorkorderList, BigDecimal unQualifySize) {
        BigDecimal unQualifySizeVal = BigDecimal.valueOf(unQualifySize.doubleValue());
        if (unQualifySize.doubleValue() > 0) {
            DoubleSummaryStatistics sum = splitFeedbackWorkorderList.stream().map(x -> x.getQuantityFeedback().doubleValue()).collect(Collectors.summarizingDouble(x -> x));
            int size = splitFeedbackWorkorderList.size();
            BigDecimal sub = BigDecimal.ZERO;
            for (ProFeedback proFeedback : splitFeedbackWorkorderList) {
                size--;

                if (size != 0) {
                    double v = proFeedback.getQuantityFeedback().divide(BigDecimal.valueOf(sum.getSum()), 2, RoundingMode.HALF_UP).doubleValue();
                    sub = unQualifySize.multiply(new BigDecimal(v)).setScale(0, RoundingMode.HALF_UP);
                    unQualifySizeVal = unQualifySizeVal.subtract(sub);
                } else {
                    sub = unQualifySizeVal;
                }
                proFeedback.setQuantityUnqualify(sub);
            }
        }

    }


    public Map<String, Object> getFeedBackTimeMap(ProFeedback feedback) {
        List<ProStartWork> proStartWorks = proStartWorkMapper.selectListByQw(new QueryWrapper<ProStartWork>().eq("task_workunit_Id", feedback.getTaskWorkunitId()).notIn("record_type", ProStartWorkEnum.START.getType()));

        ExceptionUtil.checkTrueThrowException(CollectionUtil.isEmpty(proStartWorks), MessageUtils.message("pro.feedback.error.not.find.start"));
        List<ProStartWork> proStartWorkList = proStartWorks.stream().filter(x -> Objects.equals(x.getRecordType(), ProStartWorkEnum.FEEDBACK.getType()) || Objects.equals(x.getRecordType(), ProStartWorkEnum.CLOSE.getType())).collect(Collectors.toList());
        ExceptionUtil.checkTrueThrowException(CollectionUtil.isEmpty(proStartWorkList), MessageUtils.message("pro.feedback.error.not.data"));

        long workTimeSum = 0;
        long breakTimeSum = 0;
        if (proStartWorkList.size() > 1) {
            List<ProStartWork> startWorkList = proStartWorks.stream().filter(x -> Objects.equals(x.getRecordType(), ProStartWorkEnum.CLOSE.getType())).sorted(Comparator.comparing(ProStartWork::getIdx).reversed()).collect(Collectors.toList());
            ProStartWork proStartWork = null;
            if (CollectionUtil.isNotEmpty(startWorkList)) {
                proStartWork = startWorkList.get(0);
            } else {
                startWorkList = proStartWorks.stream().filter(x -> Objects.equals(x.getRecordType(), ProStartWorkEnum.FEEDBACK.getType())).sorted(Comparator.comparing(ProStartWork::getIdx).reversed()).collect(Collectors.toList());
                if (CollectionUtil.isNotEmpty(startWorkList)) {
                    proStartWork = startWorkList.get(0);
                }
            }

            workTimeSum = proStartWork.getWorkTimeSec() - proStartWork.getBreakTimeSec();

        } else {
            breakTimeSum = proStartWorks.stream().collect(Collectors.summarizingLong(ProStartWork::getBreakTimeSec)).getSum();
            workTimeSum = proStartWorks.stream().collect(Collectors.summarizingLong(ProStartWork::getWorkTimeSec)).getSum() - breakTimeSum;
        }

        Map<String, Object> map = new HashMap<>();
        map.put("machineTimeSecond", DataUtil.getNormalData(workTimeSum));
        map.put("breakTimeSecond", DataUtil.getNormalData(breakTimeSum));
        return map;
    }

    // 反冲料报工
    private void backflushMaterialReport(Long taskWorkunitId, SAPDtoFeedback sapDtoFeedback, ProFeedback feedback) {

        // 判断反冲料
        QueryWrapper<ProRecoilMaterial> proRecoilMaterialQueryWrapper = new QueryWrapper<>();
        proRecoilMaterialQueryWrapper.eq("task_workunit_id", taskWorkunitId);
        List<ProRecoilMaterial> proRecoilMaterials = proRecoilMaterialMapper.selectListByQw(proRecoilMaterialQueryWrapper);

        if (CollectionUtil.isNotEmpty(proRecoilMaterials)) {
            List<Long> itemIds = proRecoilMaterials.stream().map(ProRecoilMaterial::getItemId).filter(Objects::nonNull).collect(Collectors.toList());
            QueryWrapper<MdItem> queryWrapper = new QueryWrapper<>();
            queryWrapper.in(CollectionUtil.isNotEmpty(itemIds), "item_id", itemIds);
            Map<Long, String> itemCodeMap = mdItemService.selectListByQw(queryWrapper).stream().collect(Collectors.toMap(MdItem::getItemId, MdItem::getSapItemCode));

            List<SAPDtoFeedback.Item> itemList = proRecoilMaterials.stream().map(x -> {
                Long itemId = x.getItemId();
                String batchNo = x.getBatchNo();

                String sapItemCode = itemCodeMap.get(itemId);
                QueryWrapper<ProWorkOrderProcessItem> wrapper = new QueryWrapper<>();
                wrapper.eq("pw.workorder_id", feedback.getWorkorderId());
                wrapper.eq("pwop.process_id", feedback.getProcessId());
                wrapper.eq("pwopi.item_id", itemId);
                List<ProWorkOrderProcessItem> items = proWorkOrderProcessItemMapper.selectBomItemListByQw(wrapper);
                ProWorkOrderProcessItem proWorkOrderProcessItem = items.get(0);
                // 报工记录总数 / 倒冲料数据  得到 两者质检的比例关系
                double proportion = feedback.getQuantity().doubleValue() / proWorkOrderProcessItem.getQuantity().doubleValue();
                // 报工记录乘以实际报工数 得到辅料的比例
                double v = proportion * feedback.getQuantityFeedback().doubleValue();
                BigDecimal bigDecimal = new BigDecimal(v).setScale(3, RoundingMode.DOWN);

                return new SAPDtoFeedback.Item(sapItemCode, batchNo, bigDecimal);
            }).collect(Collectors.toList());

            sapDtoFeedback.setItems(itemList);
        }
    }

    @Override
    public int insertObj(ProFeedback proFeedback) {
        MdWorkstation workstation = mdWorkstationService.selectMdWorkstationByWorkstationId(proFeedback.getWorkstationId());
        ExceptionUtil.checkTrueThrowException(StringUtils.isNull(workstation), MessageUtils.message("md.workStation.error.not.exist"));
        proFeedback.setProcessId(workstation.getProcessId());
        proFeedback.setProcessCode(workstation.getProcessCode());
        proFeedback.setProcessName(workstation.getProcessName());

        return this.insertProFeedback(proFeedback);
    }


    @Override
    public int syncSap(Long recordId) {
        QueryWrapper<ProFeedback> proFeedbackQueryWrapper = new QueryWrapper<>();
        proFeedbackQueryWrapper.eq("record_id", recordId);
        List<ProFeedback> proFeedbacks = proFeedbackMapper.selectListByQw(proFeedbackQueryWrapper);
        ProFeedback proFeedback = proFeedbacks.get(0);
        this.updateProFeedback(proFeedback);

        return 1;
    }

    @Override
    public int updateObj(ProFeedback proFeedback) {
        MdWorkstation workstation = mdWorkstationService.selectMdWorkstationByWorkstationId(proFeedback.getWorkstationId());
        ExceptionUtil.checkTrueThrowException(StringUtils.isNull(workstation), MessageUtils.message("md.workStation.error.not.exist"));

        ExceptionUtil.checkTrueThrowException(!StringUtils.isNotNull(proFeedback.getQuantityQualify())
                || !StringUtils.isNotNull(proFeedback.getQuantityUnqualify()), MessageUtils.message("pro.feedback.error.error2"));


        BigDecimal quantityFeedback = proFeedback.getQuantityFeedback();
        List<ProFeedback> proFeedbacks = proFeedbackMapper.selectListByQw(new QueryWrapper<ProFeedback>().eq("record_id", proFeedback.getRecordId()));
        ExceptionUtil.checkTrueThrowException(CollectionUtil.isEmpty(proFeedbacks), MessageUtils.message("pro.feedback.error.not.data"));
        ProFeedback oldFeedback = proFeedbacks.get(0);
        proFeedback.setFeedbackCode(oldFeedback.getFeedbackCode());
        BigDecimal feedbackQuantitySubtract = quantityFeedback.subtract(oldFeedback.getQuantityFeedback());

        if (feedbackQuantitySubtract.doubleValue() == 0) {
            return 1;
        }

        BigDecimal updateUnQuality = proFeedback.getQuantityUnqualify();
        BigDecimal updateQuality = proFeedback.getQuantityQualify();
        BigDecimal oldUnQuality = oldFeedback.getQuantityUnqualify();
        BigDecimal oldQuality = oldFeedback.getQuantityQualify();
        String updateMachineTime = proFeedback.getMachineTime();
        String oldMachineTime = oldFeedback.getMachineTime();


        double v1 = updateQuality.doubleValue() - oldQuality.doubleValue();
        double v2 = updateUnQuality.doubleValue() - oldUnQuality.doubleValue();
        boolean b3 = Objects.equals(updateMachineTime, oldMachineTime);


        if (v1 == 0 && b3 && v2 == 0) {
            return 1;
        }


        Long taskId = proFeedback.getTaskId();
        ProTask thisProTask = proTaskService.selectBaseById(taskId);
        BigDecimal thisTaskQualify = thisProTask.getQuantityQualify();
        BigDecimal thisTaskUnQualify = thisProTask.getQuantityUnqualify();
        BigDecimal thisTaskWait = thisProTask.getQuantityWait();
        BigDecimal thisTaskProduced = thisProTask.getQuantityProduced();
        BigDecimal thisQuantity = thisProTask.getQuantity();

        ProTask nextProTask = proTaskService.getNextTaskByTaskId(taskId);
        BigDecimal nextTaskWait = nextProTask.getQuantityWait();


        ProTaskWorkunit proTaskWorkunit = proTaskWorkunitService.selectProTaskWorkunitByTaskWorkunitId(proFeedback.getTaskWorkunitId());

        double v2abs = Math.abs(v2);
        double taskWorkunitUnQualify = proTaskWorkunit.getQuantityUnqualify().doubleValue();
        double taskWorkunitQualify = proTaskWorkunit.getQuantityQualify().doubleValue();
        double taskWorkunitProduced = proTaskWorkunit.getQuantityProduced().doubleValue();

        if (v2 != 0) {
            if (v2 < 0) {
// 减少
                thisTaskUnQualify = BigDecimal.valueOf(thisTaskUnQualify.doubleValue() - v2abs);
                taskWorkunitUnQualify = proTaskWorkunit.getQuantityUnqualify().doubleValue() - v2abs;
                taskWorkunitProduced = proTaskWorkunit.getQuantityProduced().doubleValue() - v2abs;
                thisTaskProduced = BigDecimal.valueOf(thisTaskProduced.doubleValue() - v2abs);
                thisTaskWait = BigDecimal.valueOf(thisTaskWait.doubleValue() + v2abs);
            } else {
// 增加
                thisTaskUnQualify = BigDecimal.valueOf(thisTaskUnQualify.doubleValue() + v2abs);
                taskWorkunitUnQualify = proTaskWorkunit.getQuantityUnqualify().doubleValue() + v2abs;
                taskWorkunitProduced = proTaskWorkunit.getQuantityProduced().doubleValue() + v2abs;
                thisTaskProduced = BigDecimal.valueOf(thisTaskProduced.doubleValue() + v2abs);
                thisTaskWait = BigDecimal.valueOf(thisTaskWait.doubleValue() - v2abs);
            }
        }


        double v1abc = Math.abs(v1);
        if (v1 != 0) {
            if (v1 < 0) {
// 减少
                taskWorkunitQualify = proTaskWorkunit.getQuantityQualify().doubleValue() - v1abc;
                thisTaskQualify = BigDecimal.valueOf(thisTaskQualify.doubleValue() - v1abc);
                taskWorkunitProduced = taskWorkunitProduced - v1abc;
                thisTaskProduced = BigDecimal.valueOf(thisTaskProduced.doubleValue() - v1abc);
                thisTaskWait = BigDecimal.valueOf(thisTaskWait.doubleValue() + v1abc);
                nextTaskWait = BigDecimal.valueOf(nextTaskWait.doubleValue() - v1abc);
            } else {
// 增加
                taskWorkunitQualify = proTaskWorkunit.getQuantityQualify().doubleValue() + v1abc;
                thisTaskQualify = BigDecimal.valueOf(thisTaskQualify.doubleValue() + v1abc);
                taskWorkunitProduced = taskWorkunitProduced + v1abc;
                thisTaskProduced = BigDecimal.valueOf(thisTaskProduced.doubleValue() + v1abc);
                thisTaskWait = BigDecimal.valueOf(thisTaskWait.doubleValue() - v1abc);
                nextTaskWait = BigDecimal.valueOf(nextTaskWait.doubleValue() + v1abc);
            }
        }
        QueryWrapper<ProWorkorder> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("t1.workorder_code", proFeedback.getWorkorderCode());
        queryWrapper.notIn("t1.status", Arrays.asList(WorkorderStatusEnum.CLOSE.getValue(), WorkorderStatusEnum.CANCEL.getValue(), WorkorderStatusEnum.CANCELED.getValue()));
        List<ProWorkorder> proWorkorders = proWorkorderService.selectListByQw(queryWrapper);
        if(thisTaskWait.compareTo(BigDecimal.ZERO) < 0){
            if(thisProTask.getOrdinal() == 1){
                if(proWorkorders.size() > 0 && proWorkorders.get(0).getProductionSolutionId() != null){
                    ProProductionSolution proProductionSolution
                            = proProductionSolutionMapper.selectProProductionSolutionByProductionSolutionId(proWorkorders.get(0).getProductionSolutionId());
                    if(proProductionSolution != null && proProductionSolution.getSurpassState() != null){
                        if(!proProductionSolution.getSurpassState()){
                            //不允许超报 可报工数目 - (合格数 + 不合格数）不能小于 0
                            ExceptionUtil.checkTrueThrowException(
                                    true, "工单关联的生产版本不允许超报行为");
                        }
                    }
                }
            }else{
                ExceptionUtil.checkTrueThrowException(true, "非首工序不允许超过可报工数报工");
            }
        }
        proTaskWorkunit.setQuantityQualify(BigDecimal.valueOf(taskWorkunitQualify));
        proTaskWorkunit.setQuantityProduced(BigDecimal.valueOf(taskWorkunitProduced));
        proTaskWorkunit.setQuantityUnqualify(BigDecimal.valueOf(taskWorkunitUnQualify));

        thisProTask.setQuantityQualify(thisTaskQualify);
        thisProTask.setQuantityUnqualify( thisTaskUnQualify);
        thisProTask.setQuantityWait( thisTaskWait);
        thisProTask.setQuantityProduced( thisTaskProduced);
        nextProTask.setQuantityWait(nextTaskWait);

        proTaskService.updateProTask(thisProTask);
        proTaskService.updateProTask(nextProTask);
        if (thisTaskWait.compareTo(BigDecimal.ZERO) > 0 && !proTaskWorkunit.getStatus().equals(TaskWorkunitStatusEnum.BEGINNING.getStatus())) {
            proTaskWorkunit.setStatus(TaskWorkunitStatusEnum.BEGINNING.getStatus());
            thisProTask.setTaskWorkunitId(proTaskWorkunit.getTaskWorkunitId());
            thisProTask.setWorkunitId(proTaskWorkunit.getWorkunitId());
            createStarkWorkRecord(thisProTask);
        }

        proTaskWorkunitService.updateProTaskWorkunit(proTaskWorkunit);

        this.updateProFeedback(proFeedback);
        return 1;
    }

    private void createStarkWorkRecord(ProTask proTask) {
        QueryWrapper<ProStartWork> proStartWorkQueryWrapper = new QueryWrapper<>();
        proStartWorkQueryWrapper.eq(StringUtils.isNotEmpty(proTask.getTaskId()), "task_id", proTask.getTaskId());
        proStartWorkQueryWrapper.eq(StringUtils.isNotEmpty(proTask.getTaskWorkunitId()), "task_workunit_id", proTask.getTaskWorkunitId());
        proStartWorkQueryWrapper.eq(StringUtils.isNotEmpty(proTask.getArrangeCode()), "arrange_code", proTask.getArrangeCode());
        proStartWorkQueryWrapper.eq(StringUtils.isNotEmpty(proTask.getWorkunitId()), "workunit_id", proTask.getWorkunitId());
        List<ProStartWork> startRecords = proStartWorkMapper.selectListByQw(proStartWorkQueryWrapper).stream().filter(x -> Objects.equals(x.getRecordType(), ProStartWorkEnum.START.getType())).collect(Collectors.toList());
        if (CollectionUtil.isEmpty(startRecords)) {
            proStartWorkService.insertObj(proTask);
        }
    }

    @Override
    public Double selectQuantityQualifySum(ProFeedback proFeedback) {
        QueryWrapper<ProFeedback> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(StringUtils.isNotEmpty(proFeedback.getTaskId()), "task_id", proFeedback.getTaskId());
        queryWrapper.eq(StringUtils.isNotEmpty(proFeedback.getTaskWorkunitId()), "task_workunit_id", proFeedback.getTaskWorkunitId());
        if (StringUtils.isNotEmpty(proFeedback.getArrangeCode())) {
            List<ProWorkorder> proWorkorders = proWorkorderMapper.selectListByQw(new QueryWrapper<ProWorkorder>().eq("arrange_code", proFeedback.getArrangeCode()));
            Set<Long> workorderIds = proWorkorders.stream().map(ProWorkorder::getWorkorderId).collect(Collectors.toSet());
            queryWrapper.in(CollectionUtil.isNotEmpty(workorderIds), "workorder_id", workorderIds);
        } else {
            queryWrapper.eq(StringUtils.isNotEmpty(proFeedback.getWorkorderId()), "workorder_id", proFeedback.getWorkorderId());
        }
        DoubleSummaryStatistics collectQuantityQualify = proFeedbackMapper.selectListByQw(queryWrapper).stream().collect(Collectors.summarizingDouble(x -> DataUtil.getNormalData(x.getQuantityQualify()).doubleValue()));

        DoubleSummaryStatistics collectQuantityUnqualify = proFeedbackMapper.selectListByQw(queryWrapper).stream().collect(Collectors.summarizingDouble(x -> DataUtil.getNormalData(x.getQuantityUnqualify()).doubleValue()));
        return collectQuantityQualify.getSum() + collectQuantityUnqualify.getSum();
    }

    @Override
    public List<ProFeedback> selectListByTwId(Long taskWorkunitId) {
        return proFeedbackMapper.selectListByQw(new QueryWrapper<ProFeedback>().eq("task_workunit_id", taskWorkunitId));
    }

    @Override
    public List<feedbackTaskVo> selectProFeedbackreport(feedbackTaskVo feedbackTaskVo) {
//        QueryWrapper<feedbackTaskVo> query = new QueryWrapper<>();
//        query.eq(feedbackTaskVo.get)
//        proFeedbackMapper.selectListByQw()
        return null;
    }
}
