package com.hw.mes.service.impl;

import com.hw.common.core.constant.MesConstants;
import com.hw.common.core.exception.ServiceException;
import com.hw.common.core.utils.DateUtils;
import com.hw.common.core.utils.StringUtils;
import com.hw.common.core.utils.uuid.Seq;
import com.hw.common.security.utils.SecurityUtils;
import com.hw.mes.api.domain.MesBaseBarcodeInfo;
import com.hw.mes.domain.MesMaterialAssignInfo;
import com.hw.mes.domain.MesMaterialCheckResult;
import com.hw.mes.domain.MesProductPlan;
import com.hw.mes.domain.MesProductPlanDetail;
import com.hw.mes.domain.vo.MesProductPlanDetailVo;
import com.hw.mes.mapper.*;
import com.hw.mes.service.IMesProductPlanDetailService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 生产计划明细Service业务层处理
 *
 * @author xins
 * @date 2024-02-21
 */
@Service
public class MesProductPlanDetailServiceImpl implements IMesProductPlanDetailService {
    @Autowired
    private MesProductPlanDetailMapper mesProductPlanDetailMapper;

    @Autowired
    private MesProductPlanMapper mesProductPlanMapper;

    @Autowired
    private MesMaterialCheckResultMapper mesMaterialCheckResultMapper;

    @Autowired
    private MesBaseBarcodeInfoMapper mesBaseBarcodeInfoMapper;

    @Autowired
    private MesMaterialAssignInfoMapper mesMaterialAssignInfoMapper;

    /**
     * 查询生产计划明细
     *
     * @param planDetailId 生产计划明细主键
     * @return 生产计划明细
     */
    @Override
    public MesProductPlanDetail selectMesProductPlanDetailByPlanDetailId(Long planDetailId) {
        return mesProductPlanDetailMapper.selectMesProductPlanDetailByPlanDetailId(planDetailId);
    }

    /**
     * 查询生产计划明细列表
     *
     * @param mesProductPlanDetail 生产计划明细
     * @return 生产计划明细
     */
    @Override
    public List<MesProductPlanDetail> selectMesProductPlanDetailList(MesProductPlanDetail mesProductPlanDetail) {
        if (mesProductPlanDetail.getPlanId() == null) {
            return new ArrayList<MesProductPlanDetail>();
        }
        return mesProductPlanDetailMapper.selectMesProductPlanDetailList(mesProductPlanDetail);
    }

    /**
     * 新增生产计划明细
     *
     * @param mesProductPlanDetail 生产计划明细
     * @return 结果
     */
    @Override
    public int insertMesProductPlanDetail(MesProductPlanDetail mesProductPlanDetail) {
        mesProductPlanDetail.setCreateTime(DateUtils.getNowDate());
        return mesProductPlanDetailMapper.insertMesProductPlanDetail(mesProductPlanDetail);
    }

    /**
     * 修改生产计划明细
     *
     * @param mesProductPlanDetail 生产计划明细
     * @return 结果
     */
    @Override
    public int updateMesProductPlanDetail(MesProductPlanDetail mesProductPlanDetail) {
        mesProductPlanDetail.setUpdateTime(DateUtils.getNowDate());
        return mesProductPlanDetailMapper.updateMesProductPlanDetail(mesProductPlanDetail);
    }

    /**
     * 批量删除生产计划明细
     *
     * @param planDetailIds 需要删除的生产计划明细主键
     * @return 结果
     */
    @Override
    public int deleteMesProductPlanDetailByPlanDetailIds(Long[] planDetailIds) {
        return mesProductPlanDetailMapper.deleteMesProductPlanDetailByPlanDetailIds(planDetailIds);
    }

    /**
     * 删除生产计划明细信息
     *
     * @param planDetailId 生产计划明细主键
     * @return 结果
     */
    @Override
    public int deleteMesProductPlanDetailByPlanDetailId(Long planDetailId) {
        return mesProductPlanDetailMapper.deleteMesProductPlanDetailByPlanDetailId(planDetailId);
    }


    /**
     * 根据生产计划新增生产计划明细
     *
     * @param mesProductPlanDetailVo 生产计划明细Vo
     * @return 结果
     */
    @Override
    public int insertMesProductPlanDetails(MesProductPlanDetailVo mesProductPlanDetailVo) {
        Long planId = mesProductPlanDetailVo.getPlanId();
        MesProductPlan mesProductPlan = mesProductPlanMapper.selectMesProductPlanByPlanId(planId);

        MesProductPlanDetail queryProductPlanDetail = new MesProductPlanDetail();
        queryProductPlanDetail.setPlanId(mesProductPlanDetailVo.getPlanId());
        List<MesProductPlanDetail> mesProductPlanDetails = mesProductPlanDetailMapper.selectMesProductPlanDetailList(queryProductPlanDetail);
        if (mesProductPlanDetails != null && mesProductPlanDetails.size() > 0) {
            return 0;
        } else {
            Date currentDate = new Date();
            String userName = SecurityUtils.getUsername();
            List<MesProductPlanDetail> newMesProductPlanDetails = new ArrayList<>();
            BigDecimal planAmount = mesProductPlan.getPlanAmount();

            Long planAmountL = planAmount.longValue();
            //todo 大于100条需要拆分，每100条批量保存一次
            for (long i = 0; i < planAmountL; i++) {
                MesProductPlanDetail newMesProductPlanDetail = new MesProductPlanDetail();
                newMesProductPlanDetail.setPlanId(mesProductPlanDetailVo.getPlanId());
                newMesProductPlanDetail.setPlanCode(mesProductPlan.getPlanCode());
                newMesProductPlanDetail.setPlanDetailCode(Seq.getId(Seq.mesProductPlanDetailSeqType, Seq.mesProductPlanDetailCode));
                newMesProductPlanDetail.setPlanDetailStatus(MesConstants.MES_PRODUCT_PLAN_DETAIL_STATUS_TO_START);
                newMesProductPlanDetail.setCreateTime(currentDate);
                newMesProductPlanDetail.setCreateBy(userName);
                newMesProductPlanDetail.setIsFlag("1");
                newMesProductPlanDetails.add(newMesProductPlanDetail);
            }

            mesProductPlanMapper.batchMesProductPlanDetail(newMesProductPlanDetails);
            return newMesProductPlanDetails.size();
        }

    }


    /**
     * 开始生产计划明细
     *
     * @param mesProductPlanDetail 生产计划明细
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int startMesProductPlanDetail(MesProductPlanDetail mesProductPlanDetail) {
        MesProductPlanDetail dbProductPlanDetail = mesProductPlanDetailMapper.selectMesProductPlanDetailByPlanDetailId(mesProductPlanDetail.getPlanDetailId());
        if (dbProductPlanDetail.getPlanDetailStatus().equals(MesConstants.MES_PRODUCT_PLAN_DETAIL_STATUS_FINISH)) {
            throw new ServiceException("此生成计划明细已完成");
        }

        MesProductPlan dbProductPlan = mesProductPlanMapper.selectMesProductPlanByPlanId(dbProductPlanDetail.getPlanId());
        String planStatus = dbProductPlan.getPlanStatus();
        if (planStatus.equals(MesConstants.MES_PRODUCT_PLAN_STATUS_TO_DISPATCH)) {
            throw new ServiceException("此生产计划未派工，不能开始");
        } else if (planStatus.equals(MesConstants.MES_PRODUCT_PLAN_STATUS_FINISH)) {
            throw new ServiceException("此生产计划已结束");
        }

        //todo:在开始生产计划时，更新生产工单状态、开始时间

        Date currentDate = new Date();
        String userName = SecurityUtils.getUsername();
        Long userId = SecurityUtils.getUserId();
        if (planStatus.equals(MesConstants.MES_PRODUCT_PLAN_STATUS_DISPATCHED)) {
            dbProductPlan.setRealBeginTime(currentDate);
            dbProductPlan.setPlanStatus(MesConstants.MES_PRODUCT_PLAN_STATUS_STARTED);
            dbProductPlan.setUpdateBy(userName);
            dbProductPlan.setUpdateTime(currentDate);
            mesProductPlanMapper.updateMesProductPlan(dbProductPlan);
        }

        mesProductPlanDetail.setPlanDetailStatus(MesConstants.MES_PRODUCT_PLAN_DETAIL_STATUS_STARTED);
        mesProductPlanDetail.setUserId(userId);
        mesProductPlanDetail.setUserName(userName);
        mesProductPlanDetail.setRealBeginTime(currentDate);
        mesProductPlanDetail.setUpdateTime(currentDate);
        mesProductPlanDetail.setUpdateBy(userName);
        return mesProductPlanDetailMapper.updateMesProductPlanDetail(mesProductPlanDetail);
    }

    /**
     * 完成生产计划明细
     *
     * @param mesProductPlanDetail 生产计划明细
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int completeMesProductPlanDetail(MesProductPlanDetail mesProductPlanDetail) {
        Long planDetailId = mesProductPlanDetail.getPlanDetailId();
        MesProductPlanDetail dbProductPlanDetail = mesProductPlanDetailMapper.
                selectMesProductPlanDetailByPlanDetailId(planDetailId);
        String planDetailStatus = dbProductPlanDetail.getPlanDetailStatus();
        if (planDetailStatus.equals(MesConstants.MES_PRODUCT_PLAN_DETAIL_STATUS_TO_START)) {
            throw new ServiceException("此生产计划明细未开始");
        } else if (planDetailStatus.equals(MesConstants.MES_PRODUCT_PLAN_DETAIL_STATUS_FINISH)) {
            throw new ServiceException("此生产计划明细已结束");
        }

        Long planId = dbProductPlanDetail.getPlanId();
        MesProductPlan dbProductPlan = mesProductPlanMapper.selectMesProductPlanByPlanId(planId);
        String planStatus = dbProductPlan.getPlanStatus();
        if (planStatus.equals(MesConstants.MES_PRODUCT_PLAN_STATUS_TO_DISPATCH)) {
            throw new ServiceException("此生产计划未派工，不能结束");
        } else if (planStatus.equals(MesConstants.MES_PRODUCT_PLAN_STATUS_FINISH)) {
            throw new ServiceException("此生产计划已结束");
        }

        //校验生产计划明细校验信息（如果是多个工序只校验最后一个工序，一楼和四楼都是一个工序，暂时不校验最后一个工序），
        List<MesMaterialCheckResult> checkResults =
                mesMaterialCheckResultMapper.selectMesMaterialCheckResult(planId, planDetailId, "0," + dbProductPlan.getMaterialBomId());
        List<MesMaterialCheckResult> filterCheckResults = checkResults.stream().filter(
                        materialCheckResult -> (materialCheckResult.getCheckAmount() == null ||
                                !materialCheckResult.getCheckAmount().equals(materialCheckResult.getStandardAmount()))
                                && materialCheckResult.getCheckType().equals(MesConstants.MES_MATERIAL_BOM_CHECK_TYPE_MANUAL))
                .collect(Collectors.toList());
        String updatePlanDetailStatus = MesConstants.MES_PRODUCT_PLAN_DETAIL_STATUS_FINISH;
        if (filterCheckResults != null && !filterCheckResults.isEmpty()) {
            updatePlanDetailStatus = MesConstants.MES_PRODUCT_PLAN_DETAIL_STATUS_ABNORMAL_FINISH;
        }

        Date currentDate = new Date();
        String userName = SecurityUtils.getUsername();
        BigDecimal planAmount = null;
        String attachId = dbProductPlan.getAttachId();
        if (StringUtils.isNotEmpty(attachId)) {//如果是按图纸生产的
            String[] attachIdArr = attachId.split(",");
            planAmount = new BigDecimal(attachIdArr.length);
        } else {
            planAmount = dbProductPlan.getPlanAmount();
        }

        BigDecimal complementAmount = dbProductPlan.getCompleteAmount() == null ? BigDecimal.ZERO : dbProductPlan.getCompleteAmount();

        BigDecimal newComplementAmount = complementAmount.add(BigDecimal.ONE);
        if (newComplementAmount.compareTo(planAmount) >= 0) {
            dbProductPlan.setPlanStatus(MesConstants.MES_PRODUCT_PLAN_STATUS_FINISH);
            dbProductPlan.setRealEndTime(currentDate);


            //todo：更新生产工单状态、结束时间和完成数量（根据finalprocessFlag更新生产工单）
        }
        dbProductPlan.setCompleteAmount(newComplementAmount);
        dbProductPlan.setUpdateTime(currentDate);
        dbProductPlan.setUpdateBy(userName);
        mesProductPlanMapper.updateMesProductPlan(dbProductPlan);

        mesProductPlanDetail.setUpdateTime(currentDate);
        mesProductPlanDetail.setUpdateBy(userName);
        mesProductPlanDetail.setPlanDetailStatus(updatePlanDetailStatus);
        mesProductPlanDetail.setRealEndTime(currentDate);
        return mesProductPlanDetailMapper.updateMesProductPlanDetail(mesProductPlanDetail);
    }


    /**
     * 查询最新生产计划明细
     *
     * @param mesProductPlanDetail 生产计划明细
     * @return 生产计划明细
     */
    @Override
    public MesProductPlanDetail selectNewestMesProductPlanDetail(MesProductPlanDetail mesProductPlanDetail) {
        return mesProductPlanDetailMapper.selectNewestMesProductPlanDetail(mesProductPlanDetail);
    }


    /**
     * 查询最新生产计划明细,Join attach
     *
     * @param mesProductPlanDetail 生产计划明细
     * @return 生产计划明细
     */
    @Override
    public MesProductPlanDetail selectNewestMesProductPlanDetailJoinAttach(MesProductPlanDetail mesProductPlanDetail) {
        return mesProductPlanDetailMapper.selectNewestMesProductPlanDetailJoin(mesProductPlanDetail);
    }


    /**
     * 开始下一生产计划明细
     *
     * @param mesProductPlanDetail 生产计划明细
     * @param startType            (0：其他工位，1:五楼装配工位)
     * @return MesProductPlanDetail
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public MesProductPlanDetail startNextMesProductPlanDetail(MesProductPlanDetail mesProductPlanDetail, String startType) {
        //根据planId获取最新一条的生产计划明细
        MesProductPlanDetail newestPlanDetail = mesProductPlanDetailMapper.selectNewestMesProductPlanDetail(mesProductPlanDetail);
        //todo:在开始生产计划时，更新生产工单状态、开始时间；
        //如果此计划有最新的计划明细
        if (newestPlanDetail != null) {
            String planDetailStatus = newestPlanDetail.getPlanDetailStatus();
            //判断最新任务明细的状态
            if (!planDetailStatus.equals(MesConstants.MES_PRODUCT_PLAN_DETAIL_STATUS_FINISH)
                    && !planDetailStatus.equals(MesConstants.MES_PRODUCT_PLAN_DETAIL_STATUS_ABNORMAL_FINISH)) {
                //如果不是完成状态则不能开始下一任务明细
                throw new ServiceException("请先完成上一任务明细");
            } else {
                Date realEndTime = newestPlanDetail.getRealEndTime();
                //todo:在完成任务后需要过多久才能继续下一任务
            }
        }

        //五楼装配工位要扫码开始
        if (startType.equals(MesConstants.MES_START_TYPE_FIFTH_FLOOR_ASSEMBLE)) {
            String materialBarcode = mesProductPlanDetail.getMaterialBarcode();
            MesBaseBarcodeInfo mesBaseBarcodeInfo = mesBaseBarcodeInfoMapper.selectMesBaseBarcodeInfoByBarcodeInfo(materialBarcode);
            if (mesBaseBarcodeInfo == null) {
                throw new ServiceException("物料条码有误");
            }

//            MesMaterialAssignInfo queryMaterialAssignInfo = new MesMaterialAssignInfo();
//            queryMaterialAssignInfo.setMaterialBarcode(materialBarcode);
//            List<MesMaterialAssignInfo> mesMaterialAssignInfoList = mesMaterialAssignInfoMapper.selectMesMaterialAssignInfoList(queryMaterialAssignInfo);
//            if (mesMaterialAssignInfoList == null || mesMaterialAssignInfoList.isEmpty()) {
//                throw new ServiceException("此物料条码还没下发到工位");
//            }

        }


        MesProductPlan mesProductPlan = mesProductPlanMapper.selectMesProductPlanByPlanId(mesProductPlanDetail.getPlanId());
        //判断生产计划的状态
        String planStatus = mesProductPlan.getPlanStatus();
        if (planStatus.equals(MesConstants.MES_PRODUCT_PLAN_STATUS_TO_DISPATCH)) {
            throw new ServiceException("还未派工，不能开始");
        } else if (planStatus.equals(MesConstants.MES_PRODUCT_PLAN_STATUS_FINISH)) {
            throw new ServiceException("此生产派工已经结束");
        }

        Date currentDate = new Date();
        String userName = SecurityUtils.getUsername();
        Long userId = SecurityUtils.getUserId();

        if (planStatus.equals(MesConstants.MES_PRODUCT_PLAN_STATUS_DISPATCHED)) {//如果状态是已开始，需要修改计划的状态和开始时间
            mesProductPlan.setPlanStatus(MesConstants.MES_PRODUCT_PLAN_STATUS_STARTED);
            mesProductPlan.setRealBeginTime(currentDate);
            mesProductPlan.setUpdateTime(currentDate);
            mesProductPlan.setUpdateBy(userName);
            mesProductPlanMapper.updateMesProductPlan(mesProductPlan);
        }

        mesProductPlanDetail.setPlanDetailStatus(MesConstants.MES_PRODUCT_PLAN_DETAIL_STATUS_STARTED);
        mesProductPlanDetail.setPlanDetailCode(Seq.getId(Seq.mesProductPlanDetailSeqType, Seq.mesProductPlanDetailCode));
        mesProductPlanDetail.setPlanCode(mesProductPlan.getPlanCode());
        mesProductPlanDetail.setPlanDetailStatus(MesConstants.MES_PRODUCT_PLAN_DETAIL_STATUS_STARTED);
        mesProductPlanDetail.setIsFlag("1");
        mesProductPlanDetail.setUserId(userId);
        mesProductPlanDetail.setUserName(userName);
        mesProductPlan.setRealBeginTime(currentDate);
        mesProductPlanDetail.setCreateTime(currentDate);
        mesProductPlanDetail.setCreateBy(userName);

        mesProductPlanDetailMapper.insertMesProductPlanDetail(mesProductPlanDetail);

        return mesProductPlanDetail;
    }


}
