package com.hw.mes.service.impl;

import java.math.BigDecimal;
import java.util.*;

import com.alibaba.fastjson.JSONObject;
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.SocketUtils;
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.config.MesConfig;
import com.hw.mes.domain.*;
import com.hw.mes.domain.vo.MesAssignTaskVo;
import com.hw.mes.domain.vo.MesMaterialScanVo;
import com.hw.mes.mapper.*;
import com.hw.mes.service.IMesBaseAttachInfoService;
import com.hw.mes.service.IMesProductOrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import com.hw.common.core.utils.StringUtils;
import org.springframework.transaction.annotation.Transactional;
import com.hw.mes.service.IMesProductPlanService;

/**
 * 生产派工Service业务层处理
 *
 * @author xins
 * @date 2024-02-21
 */
@Service
public class MesProductPlanServiceImpl implements IMesProductPlanService {
    @Autowired
    private MesProductPlanMapper mesProductPlanMapper;

    @Autowired
    private IMesProductOrderService mesProductOrderService;

    @Autowired
    private IMesBaseAttachInfoService mesBaseAttachInfoService;

    @Autowired
    private MesBaseAttachInfoMapper mesBaseAttachInfoMapper;

    @Autowired
    private MesProductPlanDetailMapper productPlanDetailMapper;

    @Autowired
    private MesMaterialCheckResultMapper mesMaterialCheckResultMapper;

    @Autowired
    private MesMaterialCheckResultDetailMapper mesMaterialCheckResultDetailMapper;

    @Autowired
    private MesBaseBarcodeInfoMapper mesBaseBarcodeInfoMapper;

    @Autowired
    private MesMaterialAssignInfoMapper mesMaterialAssignInfoMapper;

    @Autowired
    private MesConfig mesConfig;

    /**
     * 查询生产派工
     *
     * @param planId 生产派工主键
     * @return 生产派工
     */
    @Override
    public MesProductPlan selectMesProductPlanByPlanId(Long planId) {
        return mesProductPlanMapper.selectMesProductPlanByPlanId(planId);
    }

    /**
     * 查询生产派工列表
     *
     * @param mesProductPlan 生产派工
     * @return 生产派工
     */
    @Override
    public List<MesProductPlan> selectMesProductPlanList(MesProductPlan mesProductPlan) {
        return mesProductPlanMapper.selectMesProductPlanList(mesProductPlan);
    }

    /**
     * 新增生产派工
     *
     * @param mesProductPlan 生产派工
     * @return 结果
     */
    @Transactional
    @Override
    public int insertMesProductPlan(MesProductPlan mesProductPlan) {
        mesProductPlan.setCreateBy(SecurityUtils.getUsername());
        mesProductPlan.setCreateTime(DateUtils.getNowDate());
        mesProductPlan.setPlanCode(Seq.getId(Seq.planCodeSeqType, Seq.planCodeCode));
        int rows = mesProductPlanMapper.insertMesProductPlan(mesProductPlan);
        //更新工单已派工数量
        MesProductOrder mesProductOrder = new MesProductOrder();
        mesProductOrder.setProductOrderId(mesProductPlan.getProductOrderId());
        mesProductOrder.setDispatchAmount(mesProductPlan.getDispatchedAmount());
        mesProductOrderService.updateMesProductOrder(mesProductOrder);
        insertMesProductPlanDetail(mesProductPlan);
        return rows;
    }

    /**
     * 修改生产派工
     *
     * @param mesProductPlan 生产派工
     * @return 结果
     */
    @Transactional
    @Override
    public int updateMesProductPlan(MesProductPlan mesProductPlan) {
        mesProductPlan.setUpdateBy(SecurityUtils.getUsername());
        mesProductPlan.setUpdateTime(DateUtils.getNowDate());
        mesProductPlanMapper.deleteMesProductPlanDetailByPlanId(mesProductPlan.getPlanId());
        insertMesProductPlanDetail(mesProductPlan);
        return mesProductPlanMapper.updateMesProductPlan(mesProductPlan);
    }

    /**
     * 批量删除生产派工
     *
     * @param planIds 需要删除的生产派工主键
     * @return 结果
     */
    @Transactional
    @Override
    public int deleteMesProductPlanByPlanIds(Long[] planIds) {
        mesProductPlanMapper.deleteMesProductPlanDetailByPlanIds(planIds);
        return mesProductPlanMapper.deleteMesProductPlanByPlanIds(planIds);
    }

    /**
     * 删除生产派工信息
     *
     * @param planId 生产派工主键
     * @return 结果
     */
    @Transactional
    @Override
    public int deleteMesProductPlanByPlanId(Long planId) {
        mesProductPlanMapper.deleteMesProductPlanDetailByPlanId(planId);
        return mesProductPlanMapper.deleteMesProductPlanByPlanId(planId);
    }

    /**
     * 新增生产计划明细信息
     *
     * @param mesProductPlan 生产派工对象
     */
    public void insertMesProductPlanDetail(MesProductPlan mesProductPlan) {
        List<MesProductPlanDetail> mesProductPlanDetailList = mesProductPlan.getMesProductPlanDetailList();
        Long planId = mesProductPlan.getPlanId();
        if (StringUtils.isNotNull(mesProductPlanDetailList)) {
            List<MesProductPlanDetail> list = new ArrayList<>();
            for (MesProductPlanDetail mesProductPlanDetail : mesProductPlanDetailList) {
                mesProductPlanDetail.setPlanId(planId);
                list.add(mesProductPlanDetail);
            }
            if (list.size() > 0) {
                mesProductPlanMapper.batchMesProductPlanDetail(list);
            }
        }
    }

    /**
     * 获取派工编号
     *
     * @return
     */
    @Override
    public String getDispatchCode() {
        return Seq.getId(Seq.dispatchCodeSeqType, Seq.dispatchCodeCode);
    }

    /**
     * 生产工单新增生产派工List
     *
     * @param mesProductPlanList 生产派工
     * @return
     */
    @Override
    public int orderAddMesProductPlanList(List<MesProductPlan> mesProductPlanList) {
        for (MesProductPlan mesProductPlan : mesProductPlanList) {
            this.insertMesProductPlan(mesProductPlan);
        }
        return 1;
    }

    /**
     * 获取生产派工附件List列表
     *
     * @param planId
     * @param attachType
     * @return
     */
    @Override
    public List<MesBaseAttachInfo> getDispatchAttachList(Long planId, String attachType) {
        MesProductPlan mesProductPlan = mesProductPlanMapper.selectMesProductPlanByPlanId(planId);
        try {
            if (attachType.equals(MesConstants.MES_ATTACH_TYPE_DRAWING)) {
                if (StringUtils.isEmpty(mesProductPlan.getAttachId())) {
                    return new ArrayList<>();
                }
                Long[] attachIds = Arrays.stream(mesProductPlan.getAttachId().split(","))
                        .map(String::trim)
                        .map(Long::parseLong)
                        .toArray(Long[]::new);
                return mesBaseAttachInfoService.selectMesBaseAttachInfoByAttachIds(attachIds);
            } else if (attachType.equals(MesConstants.MES_ATTACH_TYPE_SOP)) {
                if (StringUtils.isEmpty(mesProductPlan.getSopId())) {
                    return new ArrayList<>();
                }
                Long[] sopIds = Arrays.stream(mesProductPlan.getSopId().split(","))
                        .map(String::trim)
                        .map(Long::parseLong)
                        .toArray(Long[]::new);
                return mesBaseAttachInfoService.selectMesBaseAttachInfoByAttachIds(sopIds);
            } else {
                return new ArrayList<>();
            }
        } catch (Exception e) {
            return new ArrayList<>();
        }
    }

    /**
     * 工单撤回
     *
     * @param mesProductOrder 生产工单
     * @return
     */
    @Override
    public int productOrderRecall(MesProductOrder mesProductOrder) {
        // 检验生产派工未下达状态的可进行工单撤回
        MesProductPlan mesProductPlan = new MesProductPlan();
        mesProductPlan.setProductOrderId(mesProductOrder.getProductOrderId());
        List<MesProductPlan> mesProductPlans = mesProductPlanMapper.selectMesProductPlanList(mesProductPlan);
        for (MesProductPlan productPlan : mesProductPlans) {
            if (!productPlan.getPlanStatus().equals(MesConstants.MES_PRODUCT_PLAN_STATUS_TO_DISPATCH)
                    || !productPlan.getPlanStatus().equals(MesConstants.MES_PRODUCT_PLAN_STATUS_FINISH)) {
                throw new ServiceException("此工单已派工，无法撤回！");
            }
        }
        mesProductOrder.setOrderStatus(MesConstants.RECALL);
        // 调用仓库接口取消锁定库存
        mesProductOrder.setStockLockFlag("0");
        return mesProductOrderService.updateMesProductOrder(mesProductOrder);
    }

    /**
     * 查询生产派工列表Join product_order和base_material
     *
     * @param mesProductPlan 生产派工
     * @return 生产派工
     */
    @Override
    public List<MesProductPlan> selectMesProductPlanJoinList(MesProductPlan mesProductPlan) {
        Long stationId = SecurityUtils.getStationId();
        mesProductPlan.setStationId(stationId);
        return mesProductPlanMapper.selectMesProductPlanJoinList(mesProductPlan);
    }


    /**
     * 获取图纸列表
     *
     * @param mesProductPlan
     * @return
     */
    @Override
    public List<MesBaseAttachInfo> getDrawings(MesProductPlan mesProductPlan) {
        String attachId = mesProductPlan.getAttachId();
        List<MesBaseAttachInfo> baseAttachInfos;
        if (attachId != null) {
            MesBaseAttachInfo queryBaseAttachInfo = new MesBaseAttachInfo();
            queryBaseAttachInfo.setAttachIdStr(attachId);
            baseAttachInfos = mesBaseAttachInfoMapper.selectMesBaseAttachInfoList(queryBaseAttachInfo);
            MesProductPlanDetail queryProductPlanDetail = new MesProductPlanDetail();
            queryProductPlanDetail.setPlanId(mesProductPlan.getPlanId());
            List<MesProductPlanDetail> productPlanDetails = productPlanDetailMapper.selectMesProductPlanDetailList(queryProductPlanDetail);
            if (productPlanDetails != null && !productPlanDetails.isEmpty() && baseAttachInfos != null && !baseAttachInfos.isEmpty()) {
                productPlanDetails.forEach(productPlanDetail -> {
                    for (MesBaseAttachInfo baseAttachInfo : baseAttachInfos) {
                        if (productPlanDetail.getAttachId() != null && productPlanDetail.getAttachId().equals(baseAttachInfo.getAttachId())) {
                            baseAttachInfo.setDispatchFlag(true);
                        }
                    }
                });
            }

            return baseAttachInfos;
        }

        return null;
    }


    /**
     * 在生产时校验物料使用
     *
     * @param mesMaterialScanVo
     * @return
     */
    @Transactional
    @Override
    public int scanMaterial2Confirm(MesMaterialScanVo mesMaterialScanVo) {
        Long planId = mesMaterialScanVo.getPlanId();
        Long planDetailId = mesMaterialScanVo.getPlanDetailId();
        BigDecimal checkAmount = mesMaterialScanVo.getCheckAmount();
        String materialBarcode = mesMaterialScanVo.getMaterialBarcode();
        if (checkAmount.compareTo(BigDecimal.ZERO) <= 0) {
            throw new ServiceException("数量需大于0");
        }

        MesMaterialCheckResultDetail queryCheckResultDetail = new MesMaterialCheckResultDetail();
        queryCheckResultDetail.setMaterialBarcode(materialBarcode);
        List<MesMaterialCheckResultDetail> checkResultDetailList = mesMaterialCheckResultDetailMapper.selectMesMaterialCheckResultDetailList(queryCheckResultDetail);
        if (checkResultDetailList != null && !checkResultDetailList.isEmpty()) {
            throw new ServiceException("此物料已经验证过,无需重复验证");
        }

        MesBaseBarcodeInfo baseBarcodeInfo = mesBaseBarcodeInfoMapper.selectMesBaseBarcodeInfoByBarcodeInfo(materialBarcode);
        if (baseBarcodeInfo == null) {
            throw new ServiceException("物料条码有误");
        }
        Long materialId = baseBarcodeInfo.getMaterialId();
        String batchFlag = baseBarcodeInfo.getBatchFlag();
        String batchCode = baseBarcodeInfo.getBatchCode();
        if (!batchFlag.equals(MesConstants.IS_BATCH)) {
            if (checkAmount.compareTo(BigDecimal.ONE) != 0) {
                throw new ServiceException("数量需等于1");
            }
        }

        String userName = SecurityUtils.getUsername();
        Date currentDate = new Date();
        MesMaterialCheckResult mesMaterialCheckResult = mesMaterialCheckResultMapper.
                selectMesMaterialCheckResultByUI(planId, planDetailId, materialId);
        if (mesMaterialCheckResult == null) {
            mesMaterialCheckResult = new MesMaterialCheckResult();
            mesMaterialCheckResult.setPlanId(planId);
            mesMaterialCheckResult.setPlanDetailId(planDetailId);
            mesMaterialCheckResult.setMaterialId(materialId);
            mesMaterialCheckResult.setCheckAmount(checkAmount);
            mesMaterialCheckResult.setUpdateBy(userName);
            mesMaterialCheckResult.setUpdateTime(currentDate);
            mesMaterialCheckResultMapper.insertMesMaterialCheckResult(mesMaterialCheckResult);
        } else {
            mesMaterialCheckResult.setCheckAmount(mesMaterialCheckResult.getCheckAmount()
                    .add(checkAmount));
            mesMaterialCheckResult.setUpdateBy(userName);
            mesMaterialCheckResult.setUpdateTime(currentDate);
            mesMaterialCheckResultMapper.updateMesMaterialCheckResult(mesMaterialCheckResult);
        }

        MesMaterialCheckResultDetail mesMaterialCheckResultDetail = new MesMaterialCheckResultDetail();
        mesMaterialCheckResultDetail.setMaterialCheckResultId(mesMaterialCheckResult.getMaterialCheckResultId());
        mesMaterialCheckResultDetail.setMaterialBarcode(materialBarcode);
        mesMaterialCheckResultDetail.setBatchCode(batchCode);
        mesMaterialCheckResultDetail.setCheckAmount(checkAmount);
        mesMaterialCheckResultDetailMapper.insertMesMaterialCheckResultDetail(mesMaterialCheckResultDetail);

        return 1;
    }


    /**
     * 在五楼柜体拆分区拆分完柜体将门板下发给工位装配
     *
     * @param mesAssignTaskVo
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int assignTask(MesAssignTaskVo mesAssignTaskVo) {
        String materialBarcode = mesAssignTaskVo.getMaterialBarcode();
        MesBaseBarcodeInfo mesBaseBarcodeInfo = mesBaseBarcodeInfoMapper.selectMesBaseBarcodeInfoByBarcodeInfo(materialBarcode);
        if (mesBaseBarcodeInfo == null) {
            throw new ServiceException("物料条码有误");
        }
        if (StringUtils.isEmpty(mesBaseBarcodeInfo.getBindBarcode())) {
            throw new ServiceException("此物料条码未绑定柜体，不能下发");
        }

        MesMaterialAssignInfo queryMesMaterialAssignInfo = new MesMaterialAssignInfo();
        queryMesMaterialAssignInfo.setMaterialBarcode(materialBarcode);
        List<MesMaterialAssignInfo> mesMaterialAssignInfos = mesMaterialAssignInfoMapper.selectMesMaterialAssignInfoList(queryMesMaterialAssignInfo);
        if (mesMaterialAssignInfos != null && !mesMaterialAssignInfos.isEmpty()) {
            throw new ServiceException("此物料条码已经下发，无需重复下发");
        }


        Long stationId = mesAssignTaskVo.getStationId();
        Date currentDate = new Date();
        MesMaterialAssignInfo mesMaterialAssignInfo = new MesMaterialAssignInfo();
        mesMaterialAssignInfo.setMaterialBarcode(materialBarcode);
        mesMaterialAssignInfo.setStationId(stationId);
        mesMaterialAssignInfo.setCreateBy(SecurityUtils.getUsername());
        mesMaterialAssignInfo.setCreateTime(currentDate);

        mesMaterialAssignInfoMapper.insertMesMaterialAssignInfo(mesMaterialAssignInfo);

        Long stationNo = stationId % 10;
        JSONObject assignTaskMessageJson = new JSONObject();
        assignTaskMessageJson.put("stationNo", stationNo);
        assignTaskMessageJson.put("time", currentDate.getTime());
        assignTaskMessageJson.put("materialBarcode", materialBarcode);
        //2、订阅者读取此条信息后会给出反馈，直接写入redis，如果在10s内返回，则成功，如果10s内失败则失败

        String returnMsg = SocketUtils.
                sendAndReceive(mesConfig.getSocketServerHost(), mesConfig.getSocketServerPort(), mesConfig.getSocketServerReadTimeOut(), assignTaskMessageJson.toString());
        if (StringUtils.isEmpty(returnMsg)) {
            throw new ServiceException("下发超时，请重试");
        }

        JSONObject returnMsgJson = JSONObject.parseObject(returnMsg);
        boolean isFlag = returnMsgJson.getBoolean("isFlag");
        if (!isFlag) {
            String tipMessage = returnMsgJson.getString("message");
            throw new ServiceException(tipMessage);
        }

        return 1;

    }

    /**
     * 查询物料安装情况
     * @param hashMap (installType=1已安装,installType=2未安装)
     * @return
     */
    @Override
    public List<HashMap<String, Object>> selectMaterialInstallationCircumstance(Map hashMap) {
        List<HashMap<String, Object>> result = new ArrayList<>();
        if (hashMap.containsKey("installType") && hashMap.get("installType").equals("1")){
            result = mesMaterialCheckResultMapper.selectMaterialInstallationCircumstance(hashMap);
        }
        if (hashMap.containsKey("installType") && hashMap.get("installType").equals("2")
                && hashMap.containsKey("planDetailId") && hashMap.containsKey("materialBomId")){
            result = mesMaterialCheckResultMapper.selectMaterialUnInstallationCircumstance(hashMap);
        }
        return result;
    }


//    public String executeAssignTaskResultTask() {
//        ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
//        boolean running = true;
//        AtomicInteger i = new AtomicInteger();
//        Callable<String> task = () -> {
//            String result = "";
//            while (running) {
//                i.getAndIncrement();
//                result = redisTemplate.opsForValue().getAndDelete(MesConstants.MES_ASSIGN_TASK_RESULT_KEY);
//                System.out.println("no:" + i.get());
//                if (StringUtils.isNotEmpty(result)) {
//                    break;
//                }
//            }
//            return result;
//        };
//
//
//        try {
//            // 安排任务每秒执行一次
//            ScheduledFuture<String> result = executor.schedule(task, 1, TimeUnit.SECONDS);
//            executor.shutdown();
//            executor.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS);
//            return result.get();
//        } catch (InterruptedException e) {
//            throw new RuntimeException(e);
//        } catch (ExecutionException e) {
//            throw new RuntimeException(e);
//        }
//    }
}
