package com.rongwei.bscommon.sys.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.rongwei.bscommon.sys.dao.ApsBlankOrderDao;
import com.rongwei.bscommon.sys.dao.ApsProcessOperationOutMaterDao;
import com.rongwei.bscommon.sys.service.ApsReportRecordsService;
import com.rongwei.bscommon.sys.service.ReportCheckService;
import com.rongwei.bsentity.domain.*;
import com.rongwei.bsentity.vo.CommonUpdateProductionStatusReq;
import com.rongwei.bsentity.vo.ProcessIdRelationVo;
import com.rongwei.rwcommon.base.BaseDo;
import com.rongwei.rwcommon.base.R;
import jodd.util.StringUtil;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

import static com.rongwei.safecommon.utils.SaveConstans.WorkInProgressStatus.*;

/**
 * ReportCheckServiceImpl class
 *
 * @author XH
 * @date 2024/03/19
 */
@Service
public class ReportCheckServiceImpl implements ReportCheckService {
    public static final String NO_DELETED = "0";
    public static final String DELETED = "1";
    public static final String YES = "是";
    public static final String NO = "否";
    public static final String PENDING_PLAN_REVIEW = "待计划评审";
    public static final String VERIFIED = "已检验";
    public static final String COMPLETED = "已完工";
    public static final String REJECTS = "不良品备料";
    public static final String SEMIFINISHED_PRODUCTS = "半成品备料";
    public static final String WORK_IN_PROCESS = "在制品";
    private final Logger log = LoggerFactory.getLogger(this.getClass().getName());
    @Autowired
    private ApsReportRecordsService apsReportRecordsService;
    @Autowired
    private ApsReportOutputServiceImpl apsReportOutputService;
    @Autowired
    private ApsProcessOperationServiceImpl apsProcessOperationService;
    @Autowired
    private ApsBlankOrderDao apsBlankOrderDao;
    @Autowired
    private ApsProductionOrderServiceImpl apsProductionOrderService;
    @Autowired
    private ApsWorkInProgressInventoryServiceImpl apsWorkInProgressInventoryService;
    @Autowired
    private ApsProcessOperationOutMaterServiceImpl apsProcessOperationOutMaterService;
    @Autowired
    private ApsProcessOperationProcessEquServiceImpl apsProcessOperationProcessEquService;
    @Autowired
    private ApsProcessOperationOutMaterDao apsProcessOperationOutMaterDao;

    /**
     * 保存检验结果后更新相关信息
     *
     * @param id
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public R updateRelevantInformation(String id) {
        log.info("保存检验结果后更新相关信息");
        if (StringUtil.isBlank(id)) {
            log.debug("参数为空");
            return R.error("报工检验参数异常");
        }
        // 获取报工记录
        ApsReportRecordsDo reportRecordsDo = apsReportRecordsService.getById(id);
        if (reportRecordsDo == null) {
            log.error("无法根据ID：{}获取到报工记录", id);
            return R.error("无法获取到报工记录");
        }
//        if (VERIFIED.equals(reportRecordsDo.getCheckstatus())) {
//            log.error("当前报工记录已检验无法再次检验");
//            return R.error("当前报工记录已检验无法再次检验");
//        }
        // 获取当前报工记录对应的工序作业记录
        ApsProcessOperationProcessEquDo currentProcessOperationEqu = apsProcessOperationProcessEquService.getById(reportRecordsDo.getProcessequid());
        if (currentProcessOperationEqu == null) {
            log.error("无法找到当前报工记录对应的工序作业信息");
            return R.error("无法找到当前报工记录对应的工序作业信息");
        }
        String processOperationEquId = currentProcessOperationEqu.getId();
        // 获取工序作业主表信息
        ApsProcessOperationDo currentProcessOperationMainDo = apsProcessOperationService.getOne(new LambdaQueryWrapper<ApsProcessOperationDo>()
                .eq(ApsProcessOperationDo::getId, reportRecordsDo.getProcessoperationid()).eq(BaseDo::getDeleted, NO_DELETED));
        if (currentProcessOperationMainDo == null) {
            log.error("无法根据ID：{}获取到工序作业信息", id);
            return R.error("无法获取到工序作业信息");
        }
        if (StringUtils.isBlank(currentProcessOperationMainDo.getBlankid())) {
            log.error("无法根据工序获取到生产订单信息");
            return R.error("无法获取到生产订单信息");
        }
        // 前道工序作业ID
        String previousprocessid = currentProcessOperationMainDo.getPreviousprocessid();
        // 获取工序作业对应的输出物料信息
        ApsProcessOperationOutMaterDo operationOutMaterDoList = apsProcessOperationOutMaterService.getOne(new LambdaQueryWrapper<ApsProcessOperationOutMaterDo>()
                .eq(ApsProcessOperationOutMaterDo::getMainid, currentProcessOperationMainDo.getId())
                .eq(BaseDo::getDeleted, NO_DELETED), false);
        if (operationOutMaterDoList == null) {
            log.error("无法根据工序作业ID:{}获取对应的输出物料信息", currentProcessOperationMainDo.getId());
            return R.error("无法获取到对应的输出物料信息");
        }
        // 获取该工序生成的物料输出信息
        List<ApsReportOutputDo> reportOutputDos = apsReportOutputService.list(new LambdaQueryWrapper<ApsReportOutputDo>()
//                .eq(ApsReportOutputDo::getCheckstatus,"待检验")
                .eq(ApsReportOutputDo::getMainid, id)
                .eq(BaseDo::getDeleted, NO_DELETED));
        if (reportOutputDos.isEmpty()) {
            log.error("无法根据ID：{}获取到输出物料信息", id);
            return R.error("无法获取到输出物料信息");
        }
        //获取批量计划
        ApsBlankOrderDo blankOrderDo = apsBlankOrderDao.selectById(currentProcessOperationMainDo.getBlankid());
        if (blankOrderDo == null) {
            log.error("无法根据ID：{}找到对应的订单信息", currentProcessOperationMainDo.getBlankid());
            return R.error("无法获取订单信息");
        }
        if (StringUtils.isBlank(blankOrderDo.getProductionorderid())) {
            log.error("坯料计划对应的订单ID为空");
            return R.error("无法通过坯料计划找到订单信息");
        }
        // 获取订单信息
        ApsProductionOrderDo productionOrderDo = apsProductionOrderService.getById(blankOrderDo.getProductionorderid());
        if (productionOrderDo == null) {
            log.error("无法根据ID:{},获取到订单信息", blankOrderDo.getProductionorderid());
            return R.error("无法找到订单信息");
        }

        // 获取检验不合格批次的数量
        List<ApsReportOutputDo> unqualificationOutPutList = reportOutputDos.stream()
                .filter(info -> NO.equals(info.getQualified()))
                .collect(Collectors.toList());
        // 检验合格的数量信息
        List<ApsReportOutputDo> qualifiedOutPutList = reportOutputDos.stream()
                .filter(info -> YES.equals(info.getQualified()))
                .collect(Collectors.toList());
        if (unqualificationOutPutList.isEmpty() && qualifiedOutPutList.isEmpty()) {
            log.debug("暂无检验的数据");
            return R.ok("暂无需要检验的数据");
        }
        // modify at [ 2024-06-28 11:44:04 ] by xh: 修改获取下一个工序作业的逻辑
        /**
         * 当前报工记录的输出物料ID和下一个工序作业的输入物料匹配 找到需要更新待加工料卷批次号的工序作业明细信息
         */
        String nextProcessId = currentProcessOperationMainDo.getNextprocessid();
        // 输出物料ID
        List<String> outputMaterialId = reportOutputDos.stream().map(ApsReportOutputDo::getOutputid).distinct().collect(Collectors.toList());
        // 获取当前工序对应的后道工序信息
        List<ApsProcessOperationDo> nextProcessOperationDos = new ArrayList<>();
        // 当前工序作业的下一个工序作业ID
        List<String> nextProcessIds = new ArrayList<>();
        if (StringUtils.isNotBlank(nextProcessId)) {
            // 找到可以更新待加工料卷批次号的工序作业信息
            nextProcessOperationDos = apsProcessOperationService.list(new LambdaQueryWrapper<ApsProcessOperationDo>()
                    .in(ApsProcessOperationDo::getId, Arrays.asList(nextProcessId.split(",")))
                    .in(ApsProcessOperationDo::getPlaninputid, outputMaterialId)
                    .eq(BaseDo::getDeleted, NO_DELETED));
            nextProcessIds.addAll(nextProcessOperationDos.stream().map(ApsProcessOperationDo::getId).collect(Collectors.toList()));
        }

        // 获取当前报工作业对应的在制品信息
        List<ApsWorkInProgressInventoryDo> apsWorkInProgressInventoryDos = apsWorkInProgressInventoryService.list(new LambdaQueryWrapper<ApsWorkInProgressInventoryDo>()
                .eq(ApsWorkInProgressInventoryDo::getWorkreportrecordid, id).eq(BaseDo::getDeleted, NO_DELETED));

        /******************************开始数据处理逻辑***************************************/
        // 更新合格不合格数量
        int unqualifiedQuantity = unqualificationOutPutList.size();
        // 更新合格数量
        int qualifiedQuantity = qualifiedOutPutList.size();
        // 更新已检验卷数
        int inspectQuantity = reportOutputDos.size();
        /***********************更新 工序作业输出物料的  输出已检验卷数 输出不合格卷数 输出合格卷数****************************************/
        Map<String, List<ApsReportOutputDo>> collect = reportOutputDos.stream().collect(Collectors.groupingBy(ApsReportOutputDo::getOutputid));
        collect.forEach((k, v) -> {
            long unqualifiedQty = v.stream().filter(info -> NO.equals(info.getQualified())).count();
            long passingQty = v.stream().filter(info -> YES.equals(info.getQualified())).count();
            apsProcessOperationOutMaterDao.reportCheckUpdateAboutVolumesNum(k, unqualifiedQty, passingQty, v.size());
        });
        /*********************** 工序作业输出物料 更新结束****************************************/
        // 订单信息
        //currentProductionOrderDoDispose(productionOrderDo, unqualificationOutPutList);
        log.debug("开始更新在制品库存信息");
        // 在制品
        updateArticlesProcessData(unqualificationOutPutList, qualifiedOutPutList, reportRecordsDo,
                apsWorkInProgressInventoryDos, nextProcessOperationDos, currentProcessOperationMainDo,
                operationOutMaterDoList);
        // 获取所有待加工的批次号信息
        String toBeProcessedBatchNum = apsWorkInProgressInventoryDos.stream().filter(info -> WAIT_WORK.equals(info.getWorkinprocessstatus()))
                .map(ApsWorkInProgressInventoryDo::getBatchnumber).collect(Collectors.joining(","));
//        if (!qualifiedOutPutList.isEmpty()) {
//            // 获取后道工序的数据
//            nextProcessDispose(nextProcessOperationDo, qualifiedOutPutList);
//        }

        /**********************执行数据更新操作*************************/
        if (!nextProcessIds.isEmpty() && StringUtils.isNotBlank(toBeProcessedBatchNum)) {
            log.debug("开始增加后道工序作业:{}的待加工批次号：{}", nextProcessIds, toBeProcessedBatchNum);
            //更新后续工序的待加工批次号信息
            apsProcessOperationService.updateBachmaterialprocessByIds(nextProcessIds, toBeProcessedBatchNum,
                    unqualifiedQuantity);
            apsProcessOperationProcessEquService.updateBachmaterialprocessByIds(nextProcessIds, toBeProcessedBatchNum,
                    currentProcessOperationEqu.getNextprocessesids());
        }
        /***************************存在不合格批次信息时 更新更新报工记录对应订单的订单评审状态=待计划评审， 订单调整日期=今天*************************************/
        if (unqualifiedQuantity > 0) {
            LambdaUpdateWrapper<ApsProductionOrderDo> lambdaUpdateWrapper = Wrappers.lambdaUpdate();
            lambdaUpdateWrapper.eq(ApsProductionOrderDo::getId,productionOrderDo.getId());
            lambdaUpdateWrapper.set(ApsProductionOrderDo::getAuditstatus,"待提交");
            lambdaUpdateWrapper.set(ApsProductionOrderDo::getChangedate,new Date());
            apsProductionOrderService.update(lambdaUpdateWrapper);
        }
        /************************更新工序*******************************/
        // 更新工序主表的 已检验卷数，不合格卷数，合格卷数 , 完工状态,作业状态,生产状态
        log.debug("开始更新工序作业");
        apsProcessOperationService.updateAboutCheckBatchNum(currentProcessOperationMainDo.getId(), inspectQuantity,
                qualifiedQuantity, unqualifiedQuantity);

        log.debug("开始更新工序作业明细");
        // 更新工序作业明细表的输出已检验卷数，不合格卷数，合格卷数完工状态,作业状态,生产状态
        apsProcessOperationProcessEquService.updateAboutCheckBatchNum(processOperationEquId, inspectQuantity,
                qualifiedQuantity, unqualifiedQuantity, previousprocessid, currentProcessOperationMainDo.getId());

        /***************更新在制品信息****************************/
        List<ApsWorkInProgressInventoryDo> updateList = apsWorkInProgressInventoryDos.stream()
                .filter(info -> NO_DELETED.equals(info.getDeleted())).collect(Collectors.toList());
        if (!updateList.isEmpty()) {
            log.debug("更新在制品信息");
            apsWorkInProgressInventoryService.updateWorkinprocessstatus(apsWorkInProgressInventoryDos);
        }
        /********************************更新当前报工记录的待检验批次号*************************************/
//        apsReportRecordsService.update(new LambdaUpdateWrapper<ApsReportRecordsDo>().eq(ApsReportRecordsDo::getId, id)
//                .set(ApsReportRecordsDo::getCheckstatus, VERIFIED)
//                .set(ApsReportRecordsDo::getNeedcheckbatchnumber, ""));
        /******************************如果本次检验中存在不合格的批次 则更新后续所有工序作业的状态***************************/
        if (unqualifiedQuantity != 0 && !nextProcessIds.isEmpty()) {
            ApsProcessOperationDo apsProcessOperationDo = apsProcessOperationService.getById(currentProcessOperationMainDo.getId());
            /**
             *且当前工序作业已完成 则更新后续所有
             *工序作业明细和工序作业的 相关信息
             *(工序作业明细) 完工状态 实际完工时间
             *(工序作业) 完工状态 作业状态 生产状态 实际完工时间
             */
            if (COMPLETED.equals(apsProcessOperationDo.getClosestatus())) {
                // 获取当前工序
                List<ProcessIdRelationVo> allNextProcessOperationById = apsProcessOperationService.getAllNextProcessOperationById(nextProcessIds);
                apsProcessOperationProcessEquService.updateAboutStateByProcessId(allNextProcessOperationById);
            }
        }
        // 更新坯料计划的作业状态

        CommonUpdateProductionStatusReq req = new CommonUpdateProductionStatusReq();
        req.setProcessOperationEquId(processOperationEquId);
        req.setProcessOperationId(currentProcessOperationMainDo.getId());
        req.setOrderId(productionOrderDo.getId());
        req.setBlankId(blankOrderDo.getId());
        // 更新
        apsProcessOperationProcessEquService.updateProductionStatus(req);
        apsReportOutputService.update(new LambdaUpdateWrapper<ApsReportOutputDo>()
                .in(ApsReportOutputDo::getId, reportOutputDos.stream().map(ApsReportOutputDo::getId).collect(Collectors.toList()))
                .set(ApsReportOutputDo::getCheckstatus, VERIFIED));
        reportRecordsDo.setCheckstatus(VERIFIED);
        apsReportRecordsService.update(new LambdaUpdateWrapper<ApsReportRecordsDo>()
                .set(ApsReportRecordsDo::getCheckstatus, VERIFIED)
                .set(ApsReportRecordsDo::getNeedcheckbatchnumber, null)
                .eq(ApsReportRecordsDo::getId, id));
        return R.ok();
    }

    /**
     * 更新工序作业对应的订单信息
     * 如果存在不合格的批次信息 需要更新 订单相关信息
     *
     * @param productionOrderDo
     * @param unqualificationOutPutList
     */
    public void currentProductionOrderDoDispose(ApsProductionOrderDo productionOrderDo, List<ApsReportOutputDo> unqualificationOutPutList) {
        // 存在不合格的批次信息
        if (unqualificationOutPutList.isEmpty()) {
            return;
        }
        // TODO:XH add 2024/3/20 发送不合格提醒
    }

    /**
     * 更新当前输出物料的在制品信息
     *
     * @param unqualificationOutPutList     不合格批次信息
     * @param qualifiedOutPutList           合格批次信息
     * @param apsReportRecordsDo            报工记录
     * @param apsWorkInProgressInventoryDos 在制品信息
     * @param nextProcessOperationDo        后道工序信息
     * @return
     */
    public void updateArticlesProcessData(List<ApsReportOutputDo> unqualificationOutPutList,
                                          List<ApsReportOutputDo> qualifiedOutPutList,
                                          ApsReportRecordsDo apsReportRecordsDo,
                                          List<ApsWorkInProgressInventoryDo> apsWorkInProgressInventoryDos,
                                          List<ApsProcessOperationDo> nextProcessOperationDo,
                                          ApsProcessOperationDo processOperationDo,
                                          ApsProcessOperationOutMaterDo operationOutMaterDo) {

        if (apsWorkInProgressInventoryDos.isEmpty()) {
            return;
        }
        // 1.如果报工输出物料的是否合格=否，则在制品状态=备料中
        List<String> unqualificationNum = unqualificationOutPutList.stream().map(ApsReportOutputDo::getOutputnumber).collect(Collectors.toList());
        apsWorkInProgressInventoryDos.forEach(info -> {
            if (unqualificationNum.contains(info.getBatchnumber())) {
                info.setWorkinprocessstatus(WAITING);
                info.setWorkinprocesstype(REJECTS);
            }
        });

        /**
         * 1没有后续工序作业 且 报工输出物料的是否合格=是，并且报工输出物料对应工序作业输出物料的输出合格卷数<=计划成品卷数，则从在制品库存删除该在制品
         * 2.1如果报工输出物料的是否合格=是，并且报工输出物料有对应后道工序作业，并且报工输出物料对应工序作业输出物料的输出合格卷数>计划成品卷数+报工输出物料对应所有后道工序作业的计划加工卷数，则在制品状态=备料中；
         * 2.2如果报工输出物料的是否合格=是，并且报工输出物料有对应后道工序作业，并且报工输出物料对应工序作业输出物料的输出合格卷数<=计划成品卷数+报工输出物料对应所有后道工序作业的计划加工卷数，则在制品状态=待加工；
         *
         */
        List<String> qualificationNum = qualifiedOutPutList.stream().map(ApsReportOutputDo::getOutputnumber).collect(Collectors.toList());
        int nextProcessingPlannedNum = nextProcessOperationDo.stream().mapToInt(info -> info.getPlanprocessrall() - (info.getCancelroll() == null ? 0 : info.getCancelroll())).sum();
        // 判断在制品是否存在库存信息
        List<String> collect = apsWorkInProgressInventoryDos.stream().map(ApsWorkInProgressInventoryDo::getBatchnumber).collect(Collectors.toList());
        if (qualificationNum.stream().anyMatch(info -> !collect.contains(info))) {
            throw new RuntimeException("无法获取当前检验产品的库存信息");
        }
        apsWorkInProgressInventoryDos.forEach(info -> {
            // 如果当前合格的批次号在在制品中不存在 不更新在制品库存信息
            if (!qualificationNum.contains(info.getBatchnumber())) {
                return;
            }
            if (nextProcessOperationDo.isEmpty()) {
                // modify at [ 2024-06-28 10:13:44 ] by xh: 根据需求不在删除在制品库存信息改为将在制品变为待入库状态
                if (processOperationDo.getOutputqualifiednum() + 1 <= operationOutMaterDo.getPlanprodrollnum()) {
//                    info.setDeleted(DELETED);
                    info.setWorkinprocesstype(WORK_IN_PROCESS);
                    info.setWorkinprocessstatus(TO_BE_PUT_INTO_STORAGE);
                } else {
                    info.setWorkinprocessstatus(WAIT_WORK);
                    info.setWorkinprocesstype(WORK_IN_PROCESS);
                }
            } else {
                // 输出合格卷数>计划成品卷数+下一个工序的(计划加工卷数-已取消卷数)
                if (processOperationDo.getOutputqualifiednum() + 1 > operationOutMaterDo.getPlanprodrollnum() + nextProcessingPlannedNum) {
                    info.setWorkinprocessstatus(WAITING);
                    info.setWorkinprocesstype(SEMIFINISHED_PRODUCTS);
                } else { // if (processOperationDo.getOutputqualifiednum() + 1 <= operationOutMaterDo.getPlanprodrollnum() + nextProcessingPlannedNum)
                    info.setWorkinprocessstatus(WAIT_WORK);
                    info.setWorkinprocesstype(WORK_IN_PROCESS);
                }
            }

            processOperationDo.setOutputqualifiednum(processOperationDo.getOutputqualifiednum() + 1);
        });
    }
}
