package com.zt.plat.module.qms.resource.material.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.zt.plat.framework.common.exception.ServiceException;
import com.zt.plat.framework.common.pojo.CommonResult;
import com.zt.plat.framework.common.pojo.PageResult;
import com.zt.plat.framework.common.util.object.BeanUtils;
import com.zt.plat.framework.security.core.LoginUser;
import com.zt.plat.framework.security.core.util.SecurityFrameworkUtils;
import com.zt.plat.module.bpm.api.task.BpmProcessInstanceApi;
import com.zt.plat.module.bpm.api.task.BpmTaskApi;
import com.zt.plat.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO;
import com.zt.plat.module.bpm.api.task.dto.BpmTaskApproveReqDTO;
import com.zt.plat.module.bpm.api.task.dto.BpmTaskRespDTO;
import com.zt.plat.module.infra.api.businessfile.dto.BusinessFileWithUrlRespDTO;
import com.zt.plat.module.qms.api.task.BMPCallbackInterface;
import com.zt.plat.module.qms.api.task.dto.QmsBpmDTO;
import com.zt.plat.module.qms.common.data.service.DataKeyCheckService;
import com.zt.plat.module.qms.common.dic.dal.dataobject.DictionaryBusinessDO;
import com.zt.plat.module.qms.common.dic.service.DictionaryBusinessService;
import com.zt.plat.module.qms.common.service.BusinessFileService;
import com.zt.plat.module.qms.enums.AdjustType;
import com.zt.plat.module.qms.enums.LockType;
import com.zt.plat.module.qms.enums.QmsBpmConstant;
import com.zt.plat.module.qms.enums.QmsCommonConstant;
import com.zt.plat.module.qms.resource.material.constant.MaterialConstants;
import com.zt.plat.module.qms.resource.material.controller.vo.*;
import com.zt.plat.module.qms.resource.material.dal.dataobject.*;
import com.zt.plat.module.qms.resource.material.dal.mapper.MaterialLifecycleMapper;
import com.zt.plat.module.qms.resource.material.enums.MaterialAcceptStatus;
import com.zt.plat.module.qms.resource.material.enums.MaterialFlowType;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.zt.plat.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.zt.plat.framework.common.exception.util.ServiceExceptionUtil.exception0;
import static com.zt.plat.module.qms.enums.ErrorCodeConstants.ERROR_CODE_MODULE_COMMON;
import static com.zt.plat.module.qms.enums.ErrorCodeConstants.MATERIAL_LIFECYCLE_NOT_EXISTS;
import static com.zt.plat.module.qms.enums.QmsBpmConstant.BPM_CALLBACK_BEAN_NAME;

/**
 * 物料通用流程,物料验收、退换货 Service 实现类 
 *
 * @author 后台管理
 */
@Slf4j
@Service("materialLifecycleService")
@Validated
public class MaterialLifecycleServiceImpl implements MaterialLifecycleService , BMPCallbackInterface {

    @Resource
    private MaterialLifecycleMapper materialLifecycleMapper;

    @Autowired
    private MaterialBatchService materialBatchService;

    @Autowired
    private MaterialLifecycleDetailService materialLifecycleDetailService;

    @Autowired
    private BpmTaskApi bpmTaskApi;

    @Autowired
    private BpmProcessInstanceApi bpmProcessInstanceApi;

    @Autowired
    private DataKeyCheckService dataKeyCheckService;

    @Autowired
    private DictionaryBusinessService dictionaryBusinessService;
    @Autowired
    private MaterialProductService materialProductService;
    @Autowired
    private BusinessFileService businessFileService;
    @Autowired
    private MaterialInfomationService materialInfomationService;
    @Autowired
    private MaterialInventoryOutboundService materialInventoryOutboundService;

    @Transactional
    @Override
    public MaterialLifecycleRespVO createMaterialLifecycle(MaterialLifecycleSaveReqVO createReqVO) {

        MaterialLifecycleDO mtrlLfc = BeanUtils.toBean(createReqVO, MaterialLifecycleDO.class);
        mtrlLfc.setSubmitStatus(0);
        String loginUserNickname = SecurityFrameworkUtils.getLoginUserNickname();
        LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
        if (loginUser == null) throw new ServiceException(1_032_160_000, "登录用户不存在");
        mtrlLfc.setApplyUser(loginUserNickname)
                .setApplyUserId(loginUser.getId())
                .setApplyDepartment(loginUser.getVisitDeptName())
                .setApplyDepartmentId(loginUser.getVisitDeptId())
                .setApplyTime(LocalDateTime.now());
        mtrlLfc.setFlowStatus(QmsCommonConstant.NOT_START);
        // 插入
        materialLifecycleMapper.insert(mtrlLfc);
        List<MaterialLifecycleDetailSaveReqVO> detailList = createReqVO.getDetailList();
        if (CollUtil.isEmpty(detailList))
            return BeanUtils.toBean(mtrlLfc, MaterialLifecycleRespVO.class);

        // 根据业务类型组装明细
        List<MaterialLifecycleDetailDO> detailDOS = getLifecycleDetailDOSByBusinessType(detailList, mtrlLfc);
        materialLifecycleDetailService.saveBatch(detailDOS);

        // 如果有退换货，锁定相关退换货资源
        if (MaterialFlowType.return_material.getName().equals(mtrlLfc.getBusinessType())
                || MaterialFlowType.exchange_material.getName().equals(mtrlLfc.getBusinessType())) {
            lockReturnExchangeResources(detailDOS, LockType.lock);
        }
        // 如果有物料检定，需要锁定检定数量
        if (MaterialFlowType.verify_calibrate.getName().equals(mtrlLfc.getBusinessType())) {
            lockVerifyCalibrateResources(detailDOS, LockType.lock);
        }
        return BeanUtils.toBean(mtrlLfc, MaterialLifecycleRespVO.class);
    }

    private void lockVerifyCalibrateResources(List<MaterialLifecycleDetailDO> detailDOS, LockType lockType) {
        // 批次
        List<MaterialLifecycleDetailDO> batches = detailDOS.stream().filter(detail -> detail.getBatchId() != null).toList();
        if (CollUtil.isNotEmpty(batches)) {
            materialBatchService.lockBatchVerifyCalibrateCount(batches, lockType);
        }
    }

    private void lockReturnExchangeResources(List<MaterialLifecycleDetailDO> detailDOS, LockType lockType) {
        // 批次
        List<MaterialLifecycleDetailDO> batches = detailDOS.stream().filter(detail -> detail.getBatchId() != null).toList();
        // 工段
        List<MaterialLifecycleDetailDO> gongs = detailDOS.stream().filter(detail -> detail.getBatchGongduanId() != null).toList();
        // 实例
        List<MaterialLifecycleDetailDO> infomations = detailDOS.stream().filter(detail -> detail.getInfomationId() != null).toList();
        if (CollUtil.isNotEmpty(batches)) {
            materialBatchService.lockBatchReturnExchangeCount(batches, lockType);
        }
        if (CollUtil.isNotEmpty(gongs)) {
            materialBatchService.lockGongduanReturnExchangeCount(gongs, lockType);
        }
        if (CollUtil.isNotEmpty(infomations)) {
            materialInfomationService.lockInfomationInbOrOutbStatus(infomations, lockType);
        }
    }

    private void updateReturnExchangeResources(List<MaterialLifecycleDetailDO> detailDOS, AdjustType adjustType) {
        // 批次
        List<MaterialLifecycleDetailDO> batches = detailDOS.stream().filter(detail -> detail.getBatchId() != null).toList();
        // 工段
        List<MaterialLifecycleDetailDO> gongs = detailDOS.stream().filter(detail -> detail.getBatchGongduanId() != null).toList();
        // 实例
        List<MaterialLifecycleDetailDO> infomations = detailDOS.stream().filter(detail -> detail.getInfomationId() != null).toList();
        if (CollUtil.isNotEmpty(batches)) {
            materialBatchService.updateBatchReturnExchangeCount(batches, adjustType);
        }
        if (CollUtil.isNotEmpty(gongs)) {
            materialBatchService.updateGongduanReturnExchangeCount(gongs, adjustType);
        }
        if (CollUtil.isNotEmpty(infomations)) {
            materialInfomationService.updateInfomationInbOrOutbStatus(infomations, adjustType);
        }
    }

    private List<MaterialLifecycleDetailDO> getLifecycleDetailDOSByBusinessType(List<MaterialLifecycleDetailSaveReqVO> detailList, MaterialLifecycleDO mtrlLfc) {
        MaterialFlowType type = MaterialFlowType.fromName(mtrlLfc.getBusinessType());

        return switch (type) {
            case acceptance -> getLifecycleDetailDOSByAcceptance(detailList, mtrlLfc);
            case make_apply -> getLifecycleDetailDOSByMakeApply(detailList, mtrlLfc);
            case return_material,
                 exchange_material ->
                    getLifecycleDetailDOSByReturnExchangeMaterial(detailList, mtrlLfc);
            case verify_calibrate -> getLifecycleDetailDOSByVerifyCalibrate(detailList, mtrlLfc);
        };
    }

    /**
     * 工段列表转流程明细列表
     *
     */
    private List<MaterialLifecycleDetailDO> getLifecycleDetailDOsByGongs(List<MaterialBatchDO> gongs, MaterialLifecycleDO mtrlLfc) {
        return gongs.stream().map(gong -> {
            MaterialLifecycleDetailDO detailDO = new MaterialLifecycleDetailDO();
            detailDO.setLifecycleId(mtrlLfc.getId())
                    .setProductId(gong.getProductId()).setBatchId(gong.getParentId())
                    .setBatchGongduanId(gong.getId()).setBusinessType(mtrlLfc.getBusinessType())
                    .setAssayFlag(gong.getAssayFlag())
                    .setTreatmentStatus(0);
            return detailDO;
        }).toList();
    }

    @Transactional
    @Override
    public void updateMaterialLifecycle(MaterialLifecycleSaveReqVO updateReqVO) {
        Long reqId = updateReqVO.getId();
        MaterialLifecycleDO lifecycleDO = materialLifecycleMapper.selectById(reqId);
        if (lifecycleDO == null) throw exception(MATERIAL_LIFECYCLE_NOT_EXISTS);
        if (lifecycleDO.getSubmitStatus() == 1) throw new ServiceException(1_032_160_000, "流程已提交，不可修改");
        List<MaterialLifecycleDetailSaveReqVO> detailList = updateReqVO.getDetailList();
        // 更新
        MaterialLifecycleDO mtrlLfc = BeanUtils.toBean(updateReqVO, MaterialLifecycleDO.class);
        if (CollUtil.isEmpty(detailList)) {
            materialLifecycleMapper.updateById(mtrlLfc);
            return;
        }
        // 删除原来的明细
        materialLifecycleDetailService.deleteLifecycleDetailListByLfcId(reqId);
        List<MaterialLifecycleDetailDO> oriDetailList = materialLifecycleDetailService.getDetailListByLfcId(reqId);
        // 退换货
        boolean isReturnExchangeMaterial = MaterialFlowType.return_material.getName().equals(mtrlLfc.getBusinessType())
                || MaterialFlowType.exchange_material.getName().equals(mtrlLfc.getBusinessType());
        if (isReturnExchangeMaterial)
            lockReturnExchangeResources(oriDetailList, LockType.unlock);
        // 物料检定
        boolean isVerifyCalibrate = MaterialFlowType.verify_calibrate.getName().equals(mtrlLfc.getBusinessType());
        if (isVerifyCalibrate) lockVerifyCalibrateResources(oriDetailList, LockType.unlock);
        List<MaterialLifecycleDetailDO> detailDOS = getLifecycleDetailDOSByBusinessType(detailList, mtrlLfc);
        // 保存新的明细
        materialLifecycleDetailService.saveBatch(detailDOS);
        if (isReturnExchangeMaterial) lockReturnExchangeResources(detailDOS, LockType.lock);
        if (isVerifyCalibrate) lockVerifyCalibrateResources(oriDetailList, LockType.lock);
        materialLifecycleMapper.updateById(mtrlLfc);
    }

    private List<MaterialLifecycleDetailDO> getLifecycleDetailDOSByAcceptance(List<MaterialLifecycleDetailSaveReqVO> detailList, MaterialLifecycleDO mtrlLfc) {

        List<Long> gongIds = detailList.stream().map(MaterialLifecycleDetailSaveReqVO::getBatchGongduanId).toList();
        Map<Long, Integer> gongAssayMap = detailList.stream().collect(Collectors.toMap(
                MaterialLifecycleDetailSaveReqVO::getBatchGongduanId, MaterialLifecycleDetailSaveReqVO::getAssayFlag));
        List<MaterialBatchDO> gongs = materialBatchService.getGongduanListByGongIds(gongIds);
        if (CollUtil.isEmpty(gongs) || gongs.size() != gongIds.size())
            throw new ServiceException(1_032_160_000, "工段不存在或与传入的工段数量不匹配");
        for (MaterialBatchDO gong : gongs) {
            gong.setAssayFlag(gongAssayMap.get(gong.getId()));
        }

        return getLifecycleDetailDOsByGongs(gongs, mtrlLfc);
    }

    private List<MaterialLifecycleDetailDO> getLifecycleDetailDOSByMakeApply(List<MaterialLifecycleDetailSaveReqVO> detailList, MaterialLifecycleDO mtrlLfc) {
        List<Long> pdtIds = detailList.stream().map(MaterialLifecycleDetailSaveReqVO::getProductId).toList();
        List<MaterialProductDO> products = materialProductService.getMaterialProductListByPdtIds(pdtIds);
        if (CollUtil.isEmpty(products) || products.size() != pdtIds.size())
            throw new ServiceException(1_032_160_000, "物料大类不存在或与传入的数量不匹配");

        return detailList.stream().map(detail -> {
            MaterialLifecycleDetailDO detailDO = new MaterialLifecycleDetailDO();
            detailDO.setLifecycleId(mtrlLfc.getId())
                    .setProductId(detail.getProductId())
                    .setInfluenceCount(detail.getInfluenceCount())
                    .setBusinessType(mtrlLfc.getBusinessType())
                    .setTreatmentStatus(0)
                    .setRemark(detail.getRemark());
            return detailDO;
        }).toList();
    }

    private List<MaterialLifecycleDetailDO> getLifecycleDetailDOSByReturnExchangeMaterial(List<MaterialLifecycleDetailSaveReqVO> detailList, MaterialLifecycleDO mtrlLfc) {
        // 批次
        List<MaterialLifecycleDetailSaveReqVO> reqBatches = detailList.stream().filter(detail -> detail.getBatchId() != null).toList();
        // 工段
        List<MaterialLifecycleDetailSaveReqVO> reqGongs = detailList.stream().filter(detail -> detail.getBatchGongduanId() != null).toList();
        // 实例
        List<MaterialLifecycleDetailSaveReqVO> reqInfomations = detailList.stream().filter(detail -> detail.getInfomationId() != null).toList();

        if (reqBatches.size() + reqGongs.size() + reqInfomations.size() != detailList.size())
            throw new ServiceException(1_032_160_000, "批次、工段、实例数量之和与传入的明细数量不匹配");
        List<MaterialLifecycleDetailDO> totalDetailDOS = new ArrayList<>();
        if (CollUtil.isNotEmpty(reqBatches)) {
            validBatchReturnExchangeMaterial(reqBatches);
            List<MaterialLifecycleDetailDO> detailDOS = getLifecycleDetailDOSByReturnExchangeMaterial(mtrlLfc, reqBatches);
            totalDetailDOS.addAll(detailDOS);
        }
        if (CollUtil.isNotEmpty(reqGongs)) {
            validGongReturnExchangeMaterial(reqGongs);
            List<MaterialLifecycleDetailDO> detailDOS = getLifecycleDetailDOSByReturnExchangeMaterial(mtrlLfc, reqGongs);

            totalDetailDOS.addAll(detailDOS);
        }
        if (CollUtil.isNotEmpty(reqInfomations)) {
            validInfomationReturnExchangeMaterial(reqInfomations);
            List<MaterialLifecycleDetailDO> detailDOS = getLifecycleDetailDOSByReturnExchangeMaterial(mtrlLfc, reqInfomations);
            totalDetailDOS.addAll(detailDOS);
        }
        return totalDetailDOS;
    }

    private List<MaterialLifecycleDetailDO> getLifecycleDetailDOSByVerifyCalibrate(List<MaterialLifecycleDetailSaveReqVO> detailList, MaterialLifecycleDO mtrlLfc) {
        List<MaterialLifecycleDetailSaveReqVO> reqDetails = detailList.stream().filter(detail -> detail.getBatchId() != null).toList();
        if (CollUtil.isEmpty(reqDetails) || reqDetails.size() != detailList.size())
            throw new ServiceException(1_032_160_000, "批次数量与传入的明细数量不匹配");
        List<Long> batIds = reqDetails.stream().map(MaterialLifecycleDetailSaveReqVO::getBatchId).toList();
        List<MaterialBatchDO> batches = materialBatchService.getBatchListByBatchIds(batIds);
        if (CollUtil.isEmpty(batches) || batches.size() != batIds.size())
            throw new ServiceException(1_032_160_000, "批次不存在或与传入的批次数量不匹配");
        // 检定数量检验
        Map<Long, MaterialBatchDO> batchDOMapById = batches.stream().collect(Collectors.toMap(MaterialBatchDO::getId, Function.identity()));
        for (MaterialLifecycleDetailSaveReqVO reqDetail : reqDetails) {
            MaterialBatchDO batchDO = batchDOMapById.get(reqDetail.getBatchId());
            // 可用数量
            BigDecimal availableQuantity = batchDO.getInboundQuantity().subtract(batchDO.getLockQuantity());
            if (reqDetail.getInfluenceCount().compareTo(availableQuantity) > 0)
                throw new ServiceException(1_032_160_000, String.format("检定数量超过了批次【%s】可用数量【%s】", batchDO.getBatchNo(), availableQuantity));
        }

        return reqDetails.stream().map(detail -> {
            MaterialLifecycleDetailDO detailDO = new MaterialLifecycleDetailDO();
            detailDO.setLifecycleId(mtrlLfc.getId())
                    .setBatchId(detail.getBatchId())
                    .setInfluenceCount(detail.getInfluenceCount())
                    .setBusinessType(mtrlLfc.getBusinessType())
                    .setTreatmentStatus(0)
                    .setRemark(detail.getRemark());
            return detailDO;
        }).toList();
    }

    /**
     * 校验物料退换货
     *
     */
    private void validInfomationReturnExchangeMaterial(List<MaterialLifecycleDetailSaveReqVO> reqInfomations) {
        List<Long> infomationIds = reqInfomations.stream().map(MaterialLifecycleDetailSaveReqVO::getInfomationId).toList();
        List<MaterialInfomationDO> infomations = materialInfomationService.getMaterialInfomationsByIds(infomationIds);
        if (CollUtil.isEmpty(infomations) || infomations.size() != infomationIds.size())
            throw new ServiceException(1_032_160_000, "物料信息不存在或与传入的物料信息数量不匹配");
        // 已出库的物料不可退换货
        for (MaterialInfomationDO infomation : infomations) {
            if (infomation.getUsageStatus() == 1)
                throw new ServiceException(1_032_160_000, String.format("物料【%s】已出库，不可退换货", infomation.getCode()));
        }
    }

    /**
     *   校验工段退换货
     *
     */
    private void validGongReturnExchangeMaterial(List<MaterialLifecycleDetailSaveReqVO> reqGongs) {
        List<Long> gongIds = reqGongs.stream().map(MaterialLifecycleDetailSaveReqVO::getBatchGongduanId).toList();
        List<MaterialBatchDO> gongs = materialBatchService.getGongduanListByGongIds(gongIds);
        if (CollUtil.isEmpty(gongs) || gongs.size() != gongIds.size())
            throw new ServiceException(1_032_160_000, "工段不存在或与传入的工段数量不匹配");

        // 未提交的工段不可退换货
        for (MaterialBatchDO gong : gongs) {
            if (gong.getSubmitStatus() != 1)
                throw new ServiceException(1_032_160_000, String.format("工段【%s-%s】未提交，不可退换货", gong.getBatchNo(), gong.getAssignDepartmentName()));
        }

        // 退换货量不大于剩余量
        Map<Long, MaterialBatchDO> gongsMapById = gongs.stream().collect(Collectors.toMap(MaterialBatchDO::getId, Function.identity()));
        for (MaterialLifecycleDetailSaveReqVO reqGong : reqGongs) {
            MaterialBatchDO gong = gongsMapById.get(reqGong.getBatchGongduanId());
            BigDecimal inboundQuantity = gong.getInboundQuantity();
            BigDecimal returnQuantity = gong.getReturnQuantity();
            BigDecimal replaceQuantity = gong.getReplaceQuantity();
            BigDecimal inboundEndQuantity = gong.getInboundEndQuantity();
            BigDecimal remaine = inboundQuantity.subtract(returnQuantity).subtract(replaceQuantity).subtract(inboundEndQuantity);

            if (reqGong.getInfluenceCount().compareTo(remaine) > 0)
                throw new ServiceException(1_032_160_000, String.format("退换货数量超过了批次工段【%s-%s】剩余量",
                    gongsMapById.get(reqGong.getBatchGongduanId()).getBatchNo(),
                        gongsMapById.get(reqGong.getBatchGongduanId()).getAssignDepartmentName()));
        }
    }

    /**
     * 校验批次退换货
     *
     */
    private void validBatchReturnExchangeMaterial(List<MaterialLifecycleDetailSaveReqVO> reqBatches) {
        List<Long> batchIds = reqBatches.stream().map(MaterialLifecycleDetailSaveReqVO::getBatchId).toList();
        List<MaterialBatchDO> batches = materialBatchService.getBatchListByBatchIds(batchIds);
        if (CollUtil.isEmpty(batches) || batches.size() != batchIds.size())
            throw new ServiceException(1_032_160_000, "批次不存在或与传入的批次数量不匹配");
        // 已提交的批次不可退换货
        for (MaterialBatchDO batch : batches) {
            if (batch.getSubmitStatus() == 1)
                throw new ServiceException(1_032_160_000, String.format("批次【%s】已提交，不可退换货", batch.getBatchNo()));
        }
        Map<Long, MaterialBatchDO> batchesMapById = batches.stream().collect(Collectors.toMap(MaterialBatchDO::getId, Function.identity()));
        for (MaterialLifecycleDetailSaveReqVO reqBatch : reqBatches) {
            BigDecimal inboundQuantity = batchesMapById.get(reqBatch.getBatchId()).getInboundQuantity();
            if (reqBatch.getInfluenceCount().compareTo(inboundQuantity) > 0)
                throw new ServiceException(1_032_160_000, String.format("退换货数量超过了批次【%s】数量", batchesMapById.get(reqBatch.getBatchId()).getBatchNo()));
        }
    }

    private List<MaterialLifecycleDetailDO> getLifecycleDetailDOSByReturnExchangeMaterial(MaterialLifecycleDO mtrlLfc, List<MaterialLifecycleDetailSaveReqVO> detailList) {
        return detailList.stream().map(detail -> {
            MaterialLifecycleDetailDO detailDO = new MaterialLifecycleDetailDO();
            detailDO.setLifecycleId(mtrlLfc.getId())
                    .setBatchId(detail.getBatchId())
                    .setBatchGongduanId(detail.getBatchGongduanId())
                    .setInfomationId(detail.getInfomationId())
                    .setInfluenceCount(detail.getInfluenceCount())
                    .setBusinessType(mtrlLfc.getBusinessType())
                    .setTreatmentStatus(0)
                    .setRemark(detail.getRemark());
            return detailDO;
        }).toList();
    }

    @Transactional
    @Override
    public void deleteMaterialLifecycle(Long id) {
        MaterialLifecycleDO lifecycleDO = materialLifecycleMapper.selectById(id);
        if (lifecycleDO == null) throw exception(MATERIAL_LIFECYCLE_NOT_EXISTS);
        // 已提交的流程不允许删除
        if (lifecycleDO.getSubmitStatus() == 1) throw new ServiceException(1_032_160_000, "流程已提交，不可删除");

        boolean isReturnExchangeMaterial = MaterialFlowType.return_material.getName().equals(lifecycleDO.getBusinessType())
                || MaterialFlowType.exchange_material.getName().equals(lifecycleDO.getBusinessType());
        boolean isVerifyCalibrate = MaterialFlowType.verify_calibrate.getName().equals(lifecycleDO.getBusinessType());

        if (isReturnExchangeMaterial || isVerifyCalibrate) {
            List<MaterialLifecycleDetailDO> detailList = materialLifecycleDetailService.getDetailListByLfcId(id);
            if (isReturnExchangeMaterial) this.lockReturnExchangeResources(detailList, LockType.unlock);
            if (isVerifyCalibrate) this.lockVerifyCalibrateResources(detailList, LockType.unlock);
        }
        // 删除明细
        materialLifecycleDetailService.deleteLifecycleDetailListByLfcId(id);
        // 删除流程
        materialLifecycleMapper.deleteById(id);
    }

    @Transactional
    @Override
        public void deleteMaterialLifecycleListByIds(List<Long> ids) {
        List<MaterialLifecycleDO> list = materialLifecycleMapper.selectByIds(ids);
        if (CollUtil.isEmpty(list) || list.size() != ids.size()) {
            throw exception(MATERIAL_LIFECYCLE_NOT_EXISTS);
        }
        // 存在已提交的流程不允许删除
        for (MaterialLifecycleDO lifecycle : list) {
            if (lifecycle.getSubmitStatus() == 1)
                throw new ServiceException(1_032_160_000, "存在已提交的流程，不可删除");
        }
        // 释放退换货锁定资源
        List<MaterialLifecycleDO> rtnRepLifecycleDOS = list.stream().filter(lifecycleDO ->
                MaterialFlowType.return_material.getName().equals(lifecycleDO.getBusinessType())
                        || MaterialFlowType.exchange_material.getName().equals(lifecycleDO.getBusinessType())).toList();
        if (CollUtil.isNotEmpty(rtnRepLifecycleDOS)) {
            List<Long> rtnRepIds = rtnRepLifecycleDOS.stream().map(MaterialLifecycleDO::getId).toList();
            List<MaterialLifecycleDetailDO> detailList = materialLifecycleDetailService.getDetailListByLfcIds(rtnRepIds);
            this.lockReturnExchangeResources(detailList, LockType.unlock);
        }
        // 释放检定锁定资源
        List<MaterialLifecycleDO> verifyCalibrateLifecycleDOS = list.stream().filter(lifecycleDO ->
                MaterialFlowType.verify_calibrate.getName().equals(lifecycleDO.getBusinessType())).toList();
        if (CollUtil.isNotEmpty(verifyCalibrateLifecycleDOS)) {
            List<Long> verifyCalibrateIds = verifyCalibrateLifecycleDOS.stream().map(MaterialLifecycleDO::getId).toList();
            List<MaterialLifecycleDetailDO> detailList = materialLifecycleDetailService.getDetailListByLfcIds(verifyCalibrateIds);
            this.lockVerifyCalibrateResources(detailList, LockType.unlock);
        }
        // 删除明细
        materialLifecycleDetailService.deleteLifecycleDetailListByLfcIds(ids);
        // 删除流程
        materialLifecycleMapper.deleteByIds(ids);
        }

    private void validateMaterialLifecycleExists(List<Long> ids) {
        List<MaterialLifecycleDO> list = materialLifecycleMapper.selectByIds(ids);
        if (CollUtil.isEmpty(list) || list.size() != ids.size()) {
            throw exception(MATERIAL_LIFECYCLE_NOT_EXISTS);
        }
    }

    private void validateMaterialLifecycleExists(Long id) {
        if (materialLifecycleMapper.selectById(id) == null) {
            throw exception(MATERIAL_LIFECYCLE_NOT_EXISTS);
        }
    }

    @Override
    public MaterialLifecycleRespVO getMaterialLifecycleWithDetailList(Long id) {
        MaterialLifecycleDO lifecycleDO = materialLifecycleMapper.selectById(id);
        if (lifecycleDO == null) return null;
        MaterialLifecycleRespVO respVO = BeanUtils.toBean(lifecycleDO, MaterialLifecycleRespVO.class);
        // 获取明细
        List<MaterialLifecycleDetailRespVO> detailRespVOS = materialLifecycleDetailService.getDetailListWithPdtInfoByLfcId(lifecycleDO);
        respVO.setDetailList(detailRespVOS);
        CommonResult<List<BusinessFileWithUrlRespDTO>> result = businessFileService.getBusinessFileList(id);
        respVO.setBusinessFileRet(result.getData());
        return respVO;
    }

    @Override
    public PageResult<MaterialLifecycleDO> getMaterialLifecyclePage(MaterialLifecyclePageReqVO pageReqVO) {
        PageResult<MaterialLifecycleDO> pageResult = materialLifecycleMapper.selectPage(pageReqVO);
        List<MaterialLifecycleDO> lifecycleDOS = pageResult.getList();
        if (CollUtil.isEmpty(lifecycleDOS)) return pageResult;
        lifecycleDOS.forEach(mtrlLfc -> {
            String formData = mtrlLfc.getFormData();
            if (formData != null) {
                String title = (String) JSONUtil.parseObj(formData).get("title");
                mtrlLfc.setTitle(title);
            }
        });
        pageResult.setList(lifecycleDOS);
        return pageResult;
    }

    @Transactional
    @Override
    public Boolean submitLifecycle(Long id) {
        MaterialLifecycleDO lifecycleDO = materialLifecycleMapper.selectById(id);
        if (lifecycleDO == null) throw exception(MATERIAL_LIFECYCLE_NOT_EXISTS);
        Integer submitStatus = lifecycleDO.getSubmitStatus();
        if (submitStatus == 1) throw new ServiceException(1_032_160_000, "申请已经提交过");
        lifecycleDO.setApplyTime(LocalDateTime.now());
        MaterialFlowType flowType = MaterialFlowType.fromName(lifecycleDO.getBusinessType());
        switch (flowType) {
            case acceptance ->
                // 验收需要发起流程
                this.createProcessInstance(lifecycleDO);
            case return_material, exchange_material -> {
                // 退换货需要释放锁定的资源并更新退换货数量或更新实例状态
                List<MaterialLifecycleDetailDO> detailList = materialLifecycleDetailService.getDetailListByLfcId(id);
                this.lockReturnExchangeResources(detailList, LockType.unlock);
                this.updateReturnExchangeResources(detailList, AdjustType.add);
                // 添加退换货出库记录
                materialInventoryOutboundService.addMaterialInventoryOutboundsByLfc(lifecycleDO);
            }
            case verify_calibrate -> {
                // 检定需要发起检定流程
                this.createProcessInstance(lifecycleDO);
                // TODO 释放锁定的资源
                List<MaterialLifecycleDetailDO> detailList = materialLifecycleDetailService.getDetailListByLfcId(id);
                this.lockVerifyCalibrateResources(detailList, LockType.unlock);
                // TODO 更新批次数量
                // this.updateVerifyCalibrateResources(detailList, AdjustType.add);
            }
        }

        lifecycleDO.setSubmitStatus(1);
        materialLifecycleMapper.updateById(lifecycleDO);
        return true;
    }

    @Override
    public PageResult<MaterialLifecycleRespVO> getMaterialLifecycleRespVOPage(MaterialLifecyclePageReqVO pageReqVO) {
        PageResult<MaterialLifecycleDO> lifecyclePage = getMaterialLifecyclePage(pageReqVO);
        List<MaterialLifecycleDO> lifecycleDOS = lifecyclePage.getList();
        PageResult<MaterialLifecycleRespVO> respVOPageResult = BeanUtils.toBean(lifecyclePage, MaterialLifecycleRespVO.class);
        if (CollUtil.isEmpty(lifecycleDOS)) return respVOPageResult;
        if (MaterialFlowType.make_apply.getName().equals(pageReqVO.getBusinessType())) {
            List<MaterialLifecycleRespVO> lifecycleRespVOS = respVOPageResult.getList();
            // 组装明细
            List<Long> lfcIds = lifecycleRespVOS.stream().map(MaterialLifecycleRespVO::getId).toList();
            List<MaterialLifecycleDetailRespVO> detailRespVOS = materialLifecycleDetailService.getDetailRespVOListByLfcIds(lfcIds);
            if (CollUtil.isNotEmpty(detailRespVOS)) {

                // 获取已配置的数量
                List<Long> detailIds = detailRespVOS.stream().map(MaterialLifecycleDetailRespVO::getId).toList();
                Map<Long, Long> madeCountMap = materialLifecycleDetailService.getMadeCountMapByDetailIds(detailIds);
                for (MaterialLifecycleDetailRespVO detailRespVO : detailRespVOS) {
                    Long finishedCount = madeCountMap.get(detailRespVO.getId());
                    detailRespVO.setFinishedCount(finishedCount == null ? 0L : finishedCount);
                }
                Map<Long, List<MaterialLifecycleDetailRespVO>> detailMapByLfcId = detailRespVOS.stream().collect(Collectors.groupingBy(MaterialLifecycleDetailRespVO::getLifecycleId));
                for (MaterialLifecycleRespVO lifecycleRespVO : lifecycleRespVOS) {
                    lifecycleRespVO.setDetailList(detailMapByLfcId.get(lifecycleRespVO.getId()));
                }

            }
            respVOPageResult.setList(lifecycleRespVOS);
        }
        return respVOPageResult;
    }

    @Override
    public MaterialLifecycleDO getMaterialLifecycle(Long id) {
        return materialLifecycleMapper.selectById(id);
    }

    @Override
    public List<MaterialLifecycleDetailDO> getDetailListByLfcId(Long lfcId) {
        return materialLifecycleDetailService.getDetailListByLfcId(lfcId);
    }

    private void createProcessInstance(MaterialLifecycleDO lifecycleDO) {

        String flowInstanceId = lifecycleDO.getFlowInstanceId();
        // 流程已经发起过
        if (StrUtil.isNotEmpty(flowInstanceId)) {
            CommonResult<List<BpmTaskRespDTO>> taskRet = bpmTaskApi.getTaskListByProcessInstanceId(flowInstanceId);
            List<BpmTaskRespDTO> taskList = taskRet.getData();
            if(CollUtil.isEmpty(taskList))
                throw exception0(ERROR_CODE_MODULE_COMMON, "流程任务查询失败，请联系管理员处理");
            String taskId = taskList.get(taskList.size() - 1).getId();
            //驳回后重新提交
            BpmTaskApproveReqDTO reqVO = new BpmTaskApproveReqDTO();
            reqVO.setId(taskId);
            CommonResult<Boolean> result = bpmProcessInstanceApi.approveTask(reqVO);
            if(!result.isSuccess()){
                throw exception0(ERROR_CODE_MODULE_COMMON, result.getMsg());
            }
            lifecycleDO.setFlowStatus(QmsCommonConstant.IN_PROGRESS);
            return;
        }
        // 发起流程
        LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
        if (loginUser == null) return;
        String loginUserNickname = SecurityFrameworkUtils.getLoginUserNickname();
        Long loginUserId = loginUser.getId();
        Map<String, Object> variables = new HashMap<>();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        variables.put("mainId",  lifecycleDO.getId());
        variables.put("applyUser",  loginUserNickname);
        variables.put("applyUserId", loginUserId);
        variables.put("applyDepartment",  loginUser.getVisitDeptName());
        variables.put("applyDepartmentId",  loginUser.getVisitDeptId());
        variables.put("applyTime",  sdf.format(new Date()));
        variables.put(BPM_CALLBACK_BEAN_NAME, "materialLifecycleService");
        List<MaterialLifecycleDetailDO> detailList = materialLifecycleDetailService.getDetailListByLfcId(lifecycleDO.getId());
        for (MaterialLifecycleDetailDO detailDO : detailList) {
            if (detailDO.getAssayFlag() == 1) {
                variables.put("assayFlag", 1);
                break;
            }
        }
        BpmProcessInstanceCreateReqDTO reqDTO = new BpmProcessInstanceCreateReqDTO();
        reqDTO.setBusinessKey(String.valueOf(lifecycleDO.getId()))
                                .setVariables(variables);
        // 流程key 根据业务类型动态获取
        List<DictionaryBusinessDO> items = dictionaryBusinessService.queryDictItemsByKey(MaterialConstants.DICT_MATERIAL_FLOW_TYPE);
        if (CollUtil.isEmpty(items)) throw new ServiceException(1_032_160_000, "流程配置不存在");
        Map<String, String> processKeyMap = items.stream().collect(Collectors.toMap(DictionaryBusinessDO::getName, DictionaryBusinessDO::getCustomConfig));
        MaterialFlowType materialFlowType = MaterialFlowType.fromName(lifecycleDO.getBusinessType());
        Object processKey = JSONUtil.parseObj(processKeyMap.get(materialFlowType.getName())).get("processKey");
        if (processKey == null) throw new ServiceException(1_032_160_000, "流程配置 key 不存在");

        reqDTO.setProcessDefinitionKey(processKey.toString());
        CommonResult<String> result = bpmProcessInstanceApi.createProcessInstance(loginUserId, reqDTO);
        if(!result.isSuccess()){
            throw exception0(ERROR_CODE_MODULE_COMMON, result.getMsg());
        }
        lifecycleDO.setFlowInstanceId(result.getData());
        lifecycleDO.setFlowStatus(QmsCommonConstant.IN_PROGRESS);
        lifecycleDO.setApplyUser(loginUserNickname)
                .setApplyUserId(loginUserId)
                .setApplyDepartment(loginUser.getVisitDeptName())
                .setApplyDepartmentId(loginUser.getVisitDeptId());
    }

    /**
     * 流程回调处理
     *
     */
    @Override
    public CommonResult<JSONObject> callback(QmsBpmDTO reqDTO) {
        log.debug("物料流程回调信息：{}", reqDTO.toString());

        JSONObject variables = reqDTO.getVariables();
        log.debug("流程变量：{}", variables.toString());
        String processInsId = reqDTO.getProcessInstanceId();
        String currentActivityInsId = variables.getString(QmsBpmConstant.BPM_CUR_ACTIVITY_INS_ID);
        String returnFlag = variables.getString(QmsBpmConstant.BPM_REJECT_TO_FIRST_FLAG);
        // 同一个节点需要避免重复处理
        String checkKey = currentActivityInsId;
        if(StrUtil.isEmpty(currentActivityInsId))
            checkKey = processInsId + "-create";
        if("1".equals(returnFlag))
            checkKey += "-reject";
        try{
            dataKeyCheckService.create(checkKey, this.getClass().getName());
        } catch (Exception e){
            log.error("checkKey 重复：key={}", checkKey);
            return CommonResult.success(new JSONObject());
        }
        // 流程状态处理 1-提交（含退回） 3-拒绝 4-取消流程
        String PROCESS_STATUS = variables.getString(QmsBpmConstant.PROCESS_INSTANCE_VARIABLE_STATUS);
        String businessKey = reqDTO.getBusinessKey();
        JSONArray fieldExtensions = new JSONArray();
        if(variables.containsKey(QmsBpmConstant.BPM_FIELD_EXTENSIONS)){
            fieldExtensions = variables.getJSONArray(QmsBpmConstant.BPM_FIELD_EXTENSIONS);
        }
        MaterialLifecycleDO entity = materialLifecycleMapper.selectById(Long.valueOf(businessKey));
        // String currentActivityId = variables.getString(QmsBpmConstant.BPM_CALLBACK_ACTIVITY_ID);
        // 检查是否最后一个节点
        boolean lastActivityFlag = false;
        boolean firstActivityFlag = false;
        if(!fieldExtensions.isEmpty()){
            for(int i = 0; i < fieldExtensions.size(); i++){
                JSONObject fieldExtension = fieldExtensions.getJSONObject(i);
                if(fieldExtension.getString("fieldName").equalsIgnoreCase(QmsBpmConstant.BPM_LAST_ACTIVITY_FLAG)){
                    lastActivityFlag = true;
                }
                if(fieldExtension.getString("fieldName").equalsIgnoreCase(QmsBpmConstant.BPM_FIRST_ACTIVITY_FLAG)){
                    firstActivityFlag = true;
                }
            }
        }
        // 走到检化验节点时需要发起检化验流程

        // 根据流程状态处理业务数据
        if(("1").equals(returnFlag)){
            // 驳回。流程需要配置退回到发起节点
            materialLifecycleDetailService.updateDetailTreatStatusByLfcId(entity.getId(), true);
            entity.setFlowStatus(QmsCommonConstant.REJECTED);
        } else if("3".equals(PROCESS_STATUS)){
            // 拒绝
            materialLifecycleDetailService.updateDetailTreatStatusByLfcId(entity.getId(), true);
            entity.setFlowStatus(QmsCommonConstant.REFUSED);
        } else if("4".equals(PROCESS_STATUS)){
            // 作废
            materialLifecycleDetailService.updateDetailTreatStatusByLfcId(entity.getId(), true);
            entity.setFlowStatus(QmsCommonConstant.VOID);
        } else if("1".equals(PROCESS_STATUS) || "2".equals(PROCESS_STATUS)){
            // 通过
            if(firstActivityFlag)
                // 驳回后重新提交
                entity.setFlowStatus(QmsCommonConstant.IN_PROGRESS);
            if(lastActivityFlag) {
                // 结束审批
                entity.setFlowStatus(QmsCommonConstant.COMPLETED);
                // 更新明细处理状态
                materialLifecycleDetailService.updateDetailTreatStatusByLfcId(entity.getId(), true);
                // 更新批次工段验收状态
                materialBatchService.updateMaterialBatchAcceptStatusByLfcId(entity.getId(), MaterialAcceptStatus.accepted.name());
            }

        }
        materialLifecycleMapper.updateById(entity);
        return CommonResult.success(new JSONObject());
    }
}