package com.sw.mes.yb.production.service.impl;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.sw.mes.base.global.GlobalSwitch;
import com.sw.mes.base.global.SwitchConfig;
import com.sw.mes.base.system.entity.DictionaryItem;
import com.sw.mes.base.system.service.DictionaryItemService;
import com.sw.mes.base.workinprocess.dto.PlanProcessingOrderWipStorageDto;
import com.sw.mes.base.workinprocess.service.WipStorageService;
import com.sw.mes.core.annotation.ServiceLogs;
import com.sw.mes.core.base.BaseServiceImpl;
import com.sw.mes.core.constant.ApiUrlConstants;
import com.sw.mes.core.enums.EnumValuesFactory;
import com.sw.mes.core.enums.EnumValuesFactory.WipStorageStatus;
import com.sw.mes.core.exception.BusinessException;
import com.sw.mes.core.response.Result;
import com.sw.mes.core.response.ResultCode;
import com.sw.mes.core.response.ResultGenerator;
import com.sw.mes.core.utils.BeanUtil;
import com.sw.mes.core.utils.JsonUtils;
import com.sw.mes.core.utils.NumberUtil;
import com.sw.mes.core.utils.StringUtils;
import com.sw.mes.enumvalue.EnumValuesAgv;
import com.sw.mes.utils.RestUtils;
import com.sw.mes.yb.agv.dto.AgvCallBackParamDto;
import com.sw.mes.yb.agv.dto.AgvCallDto;
import com.sw.mes.yb.agv.dto.CrystalDetailInfo;
import com.sw.mes.yb.agv.service.AgvDispatchService;
import com.sw.mes.yb.mcs.dto.InspectionBindingInfoDto;
import com.sw.mes.yb.mcs.dto.SybdCallDto;
import com.sw.mes.yb.mcs.service.YbMcsToMesService;
import com.sw.mes.yb.pad.service.ProductionPaintingLineService;
import com.sw.mes.yb.production.dao.InspectionRecordDao;
import com.sw.mes.yb.production.dto.CallTakeCrystalAgvDto;
import com.sw.mes.yb.production.dto.InspectionRecord.InspectionBackDto;
import com.sw.mes.yb.production.dto.InspectionRecord.InspectionRecordDto;
import com.sw.mes.yb.production.entity.InspectionBack;
import com.sw.mes.yb.production.entity.InspectionRecord;
import com.sw.mes.yb.production.entity.LongCrystal;
import com.sw.mes.yb.production.service.InspectionBackService;
import com.sw.mes.yb.production.service.InspectionRecordService;
import com.sw.mes.yb.production.service.LongCrystalService;
import com.sw.mes.yb.turnstore.dao.ProductionBindingTrayDao;
import com.sw.mes.yb.turnstore.entity.ProductionBindingTray;
import com.sw.mes.yb.turnstore.entity.ProductionBindingTrayLog;
import com.sw.mes.yb.turnstore.service.ProductionBindingTrayLogService;
import com.sw.mes.yb.turnstore.service.ProductionBindingTrayService;
import lombok.extern.slf4j.Slf4j;
import org.modelmapper.ModelMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.web.client.RestTemplate;

import javax.validation.Valid;
import java.math.BigDecimal;
import java.util.*;

import static com.sw.mes.base.global.GlobalSwitchNamespace.NAMESPACE_AUTOMATION;


/**
 * @Author
 * @Description：
 * @Date: Create in
 * @Modified By:
 */
@Service
@Transactional
@Slf4j
public class InspectionRecordServiceImpl extends BaseServiceImpl<InspectionRecord> implements InspectionRecordService {

    private final static String AGV_FUNCTION_KEYWORD = "圆棒送验";

    private final String SYCBD_URL = "agv/mesToMcsController/updateVehicle";

    @Autowired
    ModelMapper modelMapper;

    InspectionRecordDao dao;

    //    @Autowired
//    private TransportInspectTaskService transportInspectTaskService;
    @Autowired
    private LongCrystalService longCrystalService;
    @Autowired
    private ProductionBindingTrayService productionBindingTrayService;
    @Autowired
    private ProductionBindingTrayLogService productionBindingTrayLogService;
    @Autowired
    private AgvDispatchService agvDispatchService;
    @Autowired
    private WipStorageService wipStorageService;
    @Autowired
    private InspectionBackService inspectionBackService;
    @Autowired
    private DictionaryItemService dictionaryItemService;

    @Value("${wms.url}")
    private String wmsUrl;

    @Value("${spring.mcsServiceUrl}")
    private String mcsServiceUrl;

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private RestUtils restUtils;

    @Autowired
    private ProductionPaintingLineService productionPaintingLineService;

    @Autowired
    @Qualifier(value = "yBMesThreadPoolTaskExecutor")
    private ThreadPoolTaskExecutor ybMesThreadPoolExecutor;

    @Autowired
    private ProductionBindingTrayDao productionBindingTrayDao;

    @Autowired
    private InspectionRecordService inspectionRecordService;

    @Autowired
    private YbMcsToMesService mcsToMesService;

    @Autowired
    public void setDao(InspectionRecordDao dao) {
        super.setBaseDao(dao);
        this.dao = dao;
    }

    @Override
    public Result build(InspectionRecordDto inspectionRecordDto) {
        // 查询加工工单信息，判断是否是本站点的加工品
        PlanProcessingOrderWipStorageDto planProcessingOrderWipStorageDto = wipStorageService.selectWipStorage(inspectionRecordDto.getCrystalNo(), EnumValuesFactory.WipStorageCode.送验.getKey(), null);
        InspectionRecord inspectionRecord = fromDto(inspectionRecordDto);
        Date currentDate = new Date();

        DictionaryItem crystallineJudge = dictionaryItemService.findByThemeValueAndValueAndEnable("SendCheck", inspectionRecord.getPailNum(), true);
        if (crystallineJudge == null) {
            throw new RuntimeException("该送验车编号【"+inspectionRecord.getPailNum()+"】不存在！");
        }

        //添加/更新绑定托盘表
        ProductionBindingTray bindingTray = productionBindingTrayService.getByTrayNoAndLocationNo(inspectionRecord.getPailNum(), inspectionRecord.getLocationNo());
        if (bindingTray == null) {
            bindingTray = new ProductionBindingTray();
        } else {
            if (StringUtils.isNotBlank(bindingTray.getCrystalNo())) {
                throw new RuntimeException("该送验车该工位已绑定单晶，不可绑定");
            }
        }


        LongCrystal longCrystal = longCrystalService.get(inspectionRecord.getLongCrystalId());
//        LongCrystal lastId = longCrystalService.getLastId(longCrystal.getEquipmentCode(), longCrystal.getId());
//        if(null != lastId && EnumValuesFactory.CrystalStatus.已划线.getKey() != lastId.getCrystalStatus()){
//            throw new RuntimeException(longCrystal.getCrystalNo()+" 当前晶编的上一根长晶棒未划线,不能绑定");
//        }

        ProductionBindingTray crystalNoTray = productionBindingTrayService.getByCrystalNo(longCrystal.getCrystalNo());
        if (crystalNoTray != null) {
            throw new RuntimeException("该单晶已绑定送验车工位，不可重复绑定");
        }

        List<String> productionBindingTrays = productionBindingTrayService.findCrystalNoByTrayNo(inspectionRecordDto.getPailNum());
        for (String crystalNo : productionBindingTrays) {
            if (StringUtils.isBlank(crystalNo)) {
                continue;
            }


            LongCrystal _longCrystal = longCrystalService.findByCrystalNo(crystalNo);
            if (!StringUtils.isBlank(_longCrystal.getAgvTaskCode())) {
                throw new RuntimeException("当前载具已呼叫AGV,解绑前不能再次绑定");
            }
        }


        //送验站点进站
        if (planProcessingOrderWipStorageDto.getWipStorage().getStatus().equals(WipStorageStatus.待进站.getKey())) {
            Result result = wipStorageService.inStation(planProcessingOrderWipStorageDto.getPlanProcessingOrder().getCode(), inspectionRecord.getPailNum() + "-" + inspectionRecord.getLocationNo(), false);
            if (result.getCode().equals(ResultCode.SUCCESS.getCode())) {
                //绑定
                bindHandler(inspectionRecordDto, inspectionRecord, currentDate, bindingTray, longCrystal);
            } else {
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                throw new RuntimeException(result.getMessage());
            }
        } else {
            bindHandler(inspectionRecordDto, inspectionRecord, currentDate, bindingTray, longCrystal);
        }

        // 送验绑定、送验任务下发MCS
        SwitchConfig config = GlobalSwitch.switchConfig(NAMESPACE_AUTOMATION, "autoInspection", false);
        if(config.isEnable()) {
            String autoValue = config.getValue();
            boolean auto = false;
            if ("1".equals(autoValue)) {
                auto = true;
            } else {
                List<String> list = Arrays.asList(autoValue.split(","));
                if (list.contains(inspectionRecordDto.getSeries())) {
                    auto = true;
                }
            }
            if(auto && inspectionRecordDto.getIsAuto()) {
                //如果送验车已绑满单晶  则下发送验任务
                List<String> bindingTrays = productionBindingTrayService.findCrystalNoByTrayNo(inspectionRecordDto.getPailNum());
                if (bindingTrays.size()>=2){
                    try {
                        callAgv(inspectionRecordDto);
                    } catch (Exception e) { // 下发MCS不影响主业务
                        e.printStackTrace();
                        log.error("自动送验绑定完成下发送验任务信息至MCS", e);
                    }
                }
            }

        }

        return ResultGenerator.success(inspectionRecord);
    }


    @Override
    public void back(InspectionBackDto inspectionBackDto) {
        LongCrystal longCrystal = longCrystalService.get(inspectionBackDto.getLongCrystalId());

        if (inspectionBackDto.getWholeCrystal() != null && inspectionBackDto.getWholeCrystal() == true) {//整棒退料

            //工单出站，不进入下站，不产生子批，停止当前工单
            wipStorageService.outStation2(longCrystal.getCrystalNo(), new ArrayList<>(), true, new HashMap<>());

            longCrystal.setCrystalStatus(3);
            longCrystalService.saveOrUpdate(longCrystal);
        }else {
        	BigDecimal len = new BigDecimal(longCrystal.getLength().doubleValue()-inspectionBackDto.getBackLength().doubleValue());
        	BigDecimal wei = new BigDecimal(longCrystal.getWeight().doubleValue()-inspectionBackDto.getBackWeight().doubleValue());
        	longCrystal.setLength(len);
        	longCrystal.setWeight(wei);
        	longCrystalService.saveOrUpdate(longCrystal);
        }

        InspectionBack inspectionBack = fromDto(inspectionBackDto);
        inspectionBack.setCreateTime(new Date());
        inspectionBackService.saveOrUpdate(inspectionBack);
    }


    private void bindHandler(InspectionRecordDto inspectionRecordDto, InspectionRecord inspectionRecord,
                             Date currentDate, ProductionBindingTray bindingTray, LongCrystal longCrystal) {
        //保存绑定送验记录
        inspectionRecord.setBuildTime(currentDate);
        inspectionRecord.setSeries(longCrystal.getSeries());
        saveOrUpdate(inspectionRecord);

        //长晶棒送验状态更新

        longCrystal.setCrystalStatus(EnumValuesFactory.CrystalStatus.已绑定.getKey());
        longCrystal.setUserUpdate(inspectionRecord.getUserName());
        longCrystal.setGmtUpdate(currentDate);
        longCrystalService.saveOrUpdate(longCrystal);

        if(inspectionRecordDto.getIsAuto())
            bindingTray.setIsBinding(0);//自动绑定
        else
            bindingTray.setIsBinding(1);//人工绑定
        bindingTray.setBindingTime(currentDate);
        bindingTray.setCrystalNo(longCrystal.getCrystalNo());
        bindingTray.setTrayNo(inspectionRecord.getPailNum());
        bindingTray.setLocationNo(inspectionRecord.getLocationNo());
        bindingTray.setBindingSite("送验冷却区");
        bindingTray.setBindingPeople(inspectionRecord.getUserName());
        productionBindingTrayService.saveOrUpdate(bindingTray);


        //添加绑定托盘记录
        ProductionBindingTrayLog log = new ProductionBindingTrayLog();
        BeanUtil.copyProperties(bindingTray, log, "id");
        if(inspectionRecordDto.getIsAuto()) {
            log.setIsBinding(0);//自动绑定
            log.setBindingSite("自动送验绑定");
        } else {
            log.setIsBinding(1);//人工绑定
            log.setBindingSite("PDA送验绑定");
        }
        log.setBindingPeople(inspectionRecordDto.getUserName());
        log.setBindingTime(currentDate);
        log.setClassName(inspectionRecordDto.getTeamGroup());
        log.setClassnoname(inspectionRecordDto.getClassNo());
        log.setSeries(longCrystal.getSeries());
        log.setArea(inspectionRecordDto.getArea());
        log.setGmtCreate(currentDate);
        productionBindingTrayLogService.saveOrUpdate(log);
    }


    @Override
    public void callAgv(InspectionRecordDto inspectionRecordDto) {
        //下发物料信息
        Result resultWlxx=sendBindingInfoToMcs(inspectionRecordDto);
        if(resultWlxx.getCode()!=ResultCode.SUCCESS.getCode()){
            throw new RuntimeException("下发物料信息错误");
        }
        ProductionBindingTray crystalNoTray = productionBindingTrayService.getByCrystalNo(inspectionRecordDto.getCrystalNo());
        if (crystalNoTray == null) {
            throw new RuntimeException("该单晶未绑定送验车,无法呼叫agv");
        }
        //if(crystalNoTray.get)
        List<ProductionBindingTray> bindingTrayByTrayNo = productionBindingTrayService.findBindingTrayByTrayNo(inspectionRecordDto.getPailNum());
        if (bindingTrayByTrayNo==null){
            throw new RuntimeException("未找到绑定记录,请先绑定送验车");
        }else if (bindingTrayByTrayNo.size()<2){
            throw new RuntimeException("送验车尚未绑定满，请先绑定送验车");
        }

        InspectionRecord inspectionRecord = dao.getLastCrystalNoLog(inspectionRecordDto.getCrystalNo());
        if (inspectionRecord == null) {
            throw new RuntimeException("未找到绑定记录,请先绑定送验车");
        }

        //AGV所需晶棒编号
        List<String> _crystalNoArr = new ArrayList<String>();
        //mcs所需取段时间
        List<Date> _timeArr = new ArrayList<Date>();
        //agv所需晶棒详情
//        List<AgvCrystalInfoDto> crystalInfos = new ArrayList<AgvCrystalInfoDto>();
        List<LongCrystal> crystalInfos = new ArrayList<LongCrystal>();

        //当前提交晶棒是否存在已呼叫agv托盘上
        boolean currentCallAgved = false;
        String taskCode = "AGV调度未上线";
        List<String> productionBindingTrays = productionBindingTrayService.findCrystalNoByTrayNo(inspectionRecordDto.getPailNum());
        for (String crystalNo : productionBindingTrays) {
            if (StringUtils.isBlank(crystalNo)) {
                continue;
            }

            LongCrystal longCrystal = longCrystalService.findByCrystalNo(crystalNo);
            if (longCrystal != null) {
                if (!StringUtils.isBlank(longCrystal.getAgvTaskCode())) {
                    currentCallAgved = true;
                    taskCode = longCrystal.getAgvTaskCode();
                }
                if(longCrystal.getGmtCreate() != null){
//                    _timeArr.add(longCrystal.getGmtCreate());

                    if(null != longCrystal.getGmtCreateAdd()) {
                        //使用新字段
                        _timeArr.add(longCrystal.getGmtCreateAdd());
                    } else {
                        // 同步产出时间 完结尾的长晶棒产出时间特殊处理，增加9个小时
                        Date newDate = longCrystal.getGmtCreate();
                        newDate.setTime(longCrystal.getGmtCreate().getTime() + 145 * 6 * 60 * 1000);
                        _timeArr.add(newDate);
                    }
                }
            }


            _crystalNoArr.add(crystalNo);

//            AgvCrystalInfoDto info = new AgvCrystalInfoDto();
//            info.setCrystalNo(longCrystal.getCrystalNo());
//            info.setWeight(longCrystal.getWeight());
//            info.setLength(longCrystal.getLength());
//            info.setSpecs(longCrystal.getSpecs());
//            //todo 规格转换
//            List<DictionaryItem> toMCSProductSpec = dictionaryItemService.findByThemeValueAndEnable("ToMCSProductSpec", true);
//            Map<String, DictionaryItem> specMap = toMCSProductSpec.stream().collect(Collectors.toMap(DictionaryItem::getName, Function.identity(), (t1, t2) -> t1));
//            String specs = longCrystal.getSpecs();
//            if (specMap.containsKey(specs)){
//                longCrystal.setSpecs(specMap.get(specs).getValue());
//            } else {
//                throw new RuntimeException("未配置规格对应关系，请在数据字典进行配置");
//            }
            crystalInfos.add(longCrystal);
        }


        if (!currentCallAgved) {
            //使用方法案例
            //1。先配置AGV接口固定参数与URL
            //2。接口调用 接口调用失败抛出AgvCallException异常     , 可不用try...catch包裹 由框架自行捕捉并提示异常
            //3.请求成功返回任务编号   - 任务编号用于取消agv 回调信息对照等操作

            try {
                AgvCallDto agvCall = new AgvCallDto();
                agvCall.setKeyword(EnumValuesAgv.AGVKeyword.圆棒送验.getValue());//关键字 根据配置中的信息固定写入  : 圆棒送验
                agvCall.setStartCode(inspectionRecordDto.getLandmarkCode()); //起始位置编号  - 当前传入机台号
                agvCall.setFrockCode(inspectionRecordDto.getPailNum());//载具车编号
                //以下信息非必填
                agvCall.setCrystalNo(StringUtils.join(_crystalNoArr.toArray(), "|")); //单晶编号
                agvCall.setTime(Collections.max(_timeArr));//取段时间
                agvCall.setCrystalDetailInfo(JSON.toJSONString(crystalInfos));
                //其他信息可根据配置信息自动填充
                //目前没有对接AGV，默认呼叫成功，20220811
                List<DictionaryItem> dictionaryItems = dictionaryItemService.findByThemeValueAndItemName("callAgvUrl", "url", true);
                if (dictionaryItems.size()>0){
                    String callAgvUrl = mcsServiceUrl + "/" + ApiUrlConstants.MCS_CALL_AGV_API;
                    if(dictionaryItems.get(0).getValue().equals(callAgvUrl)){
//                    if (dictionaryItems.get(0).getValue().equals("http://10.141.0.130:8806/agv/taskAction/pullAgvTask")){
                        taskCode = agvDispatchService.callAgv(agvCall);
                    }
                }
            } catch (Exception e) {
                //暂时先去掉验证agv错误调用处理
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                throw new RuntimeException(e.getMessage());
            }

        }


        //呼叫AGV成功后处理业务逻辑

        //长晶棒送验状态更新
        Date currentDate = new Date();
        for (String crystalNo : productionBindingTrays) {
            // 查询加工工单信息，判断是否是本站点的加工品
            PlanProcessingOrderWipStorageDto planProcessingOrderWipStorageDto = wipStorageService.selectWipStorage(crystalNo, EnumValuesFactory.WipStorageCode.送验.getKey(), true);
            //送验站点进站
            Result result = wipStorageService.outStation(planProcessingOrderWipStorageDto.getPlanProcessingOrder().getCode(), null, WipStorageStatus.已进站.getKey());
            if (result.getCode() == ResultCode.SUCCESS.getCode()) {
                LongCrystal longCrystal = longCrystalService.findByCrystalNo(crystalNo);
                if (longCrystal == null) {
                    throw new RuntimeException("在长晶棒产出记录表中未找到"+crystalNo+"晶棒信息,请检查");
                }
                longCrystal.setCrystalStatus(EnumValuesFactory.CrystalStatus.已送验.getKey());
                longCrystal.setAgvTaskCode(taskCode);
                longCrystalService.saveOrUpdate(longCrystal);

                InspectionRecord _inspectionRecord = dao.getLastCrystalNoLog(crystalNo);
                //修改记录中送验时间
                _inspectionRecord.setInspectionTime(currentDate);
                saveOrUpdate(_inspectionRecord);
            }
        }

    }


    /**
     * 只送验不呼叫AGV
     * @param inspectionRecordDto
     */
    @Override
    public void sendCheck(InspectionRecordDto inspectionRecordDto) {
        ProductionBindingTray crystalNoTray = productionBindingTrayService.getByCrystalNo(inspectionRecordDto.getCrystalNo());
        if (crystalNoTray == null) {
            throw new RuntimeException("该单晶未绑定送验车,无法送验");
        }

        List<ProductionBindingTray> bindingTrayByTrayNo = productionBindingTrayService.findBindingTrayByTrayNo(inspectionRecordDto.getPailNum());
        if (bindingTrayByTrayNo==null){
            throw new RuntimeException("未找到绑定记录,请先绑定送验车");
        }else if (inspectionRecordDto.getIsSingleCrystal()){
            if (bindingTrayByTrayNo.size()!=1){
            throw new RuntimeException("送验车已绑定的单晶数量不是一颗，无法单颗人工送验！");
        }
        }else if (!inspectionRecordDto.getIsSingleCrystal()){
            if (bindingTrayByTrayNo.size()!=2){
                throw new RuntimeException("送验车尚未绑定满，请继续寻找单晶绑定在此送验车！");
            }
        }
//            if (bindingTrayByTrayNo.size()<2){
//            throw new RuntimeException("送验车尚未绑定满，请继续寻找单晶绑定在此送验车！");
//        }
        InspectionRecord inspectionRecord = dao.getLastCrystalNoLog(inspectionRecordDto.getCrystalNo());
        if (inspectionRecord == null) {
            throw new RuntimeException("未找到绑定记录,请先绑定送验车");
        }
//        List<InspectionRecord> records = dao.getRecordByPailNum(inspectionRecordDto.getPailNum());
//        if (records == null){
//            throw new RuntimeException("未找到绑定记录,请先绑定送验车");
//        }else if (records.size()<2){
//            throw new RuntimeException("送验车尚未绑定满，请先绑定送验车");
//        }

        //AGV所需晶棒编号
        List<String> _crystalNoArr = new ArrayList<String>();
        //mcs所需取段时间
        List<Date> _timeArr = new ArrayList<Date>();
        //agv所需晶棒详情
//        List<AgvCrystalInfoDto> crystalInfos = new ArrayList<AgvCrystalInfoDto>();
        List<LongCrystal> crystalInfos = new ArrayList<LongCrystal>();

        //当前提交晶棒是否存在已呼叫agv托盘上
        boolean currentCallAgved = false;
        String taskCode = "AGV调度未上线";
        List<String> productionBindingTrays = productionBindingTrayService.findCrystalNoByTrayNo(inspectionRecordDto.getPailNum());
        for (String crystalNo : productionBindingTrays) {
            if (StringUtils.isBlank(crystalNo)) {
                continue;
            }

            LongCrystal longCrystal = longCrystalService.findByCrystalNo(crystalNo);
            if (longCrystal != null) {
                if (!StringUtils.isBlank(longCrystal.getAgvTaskCode())) {
                    currentCallAgved = true;
                    taskCode = longCrystal.getAgvTaskCode();
                }
                if(longCrystal.getGmtCreate() != null){
                    _timeArr.add(longCrystal.getGmtCreate());
                }
            }


            _crystalNoArr.add(crystalNo);

//            AgvCrystalInfoDto info = new AgvCrystalInfoDto();
//            info.setCrystalNo(longCrystal.getCrystalNo());
//            info.setWeight(longCrystal.getWeight());
//            info.setLength(longCrystal.getLength());
//            info.setSpecs(longCrystal.getSpecs());
            crystalInfos.add(longCrystal);
        }


        if (!currentCallAgved) {
            //使用方法案例
            //1。先配置AGV接口固定参数与URL
            //2。接口调用 接口调用失败抛出AgvCallException异常     , 可不用try...catch包裹 由框架自行捕捉并提示异常
            //3.请求成功返回任务编号   - 任务编号用于取消agv 回调信息对照等操作

            try {
                AgvCallDto agvCall = new AgvCallDto();
                agvCall.setKeyword(EnumValuesAgv.AGVKeyword.圆棒送验.getValue());//关键字 根据配置中的信息固定写入  : 圆棒送验
                agvCall.setStartCode(inspectionRecordDto.getLandmarkCode()); //起始位置编号  - 当前传入机台号
                agvCall.setFrockCode(inspectionRecordDto.getPailNum());//载具车编号
                //以下信息非必填
                agvCall.setCrystalNo(StringUtils.join(_crystalNoArr.toArray(), "|")); //单晶编号
                agvCall.setTime(Collections.max(_timeArr));//取段时间
                agvCall.setCrystalDetailInfo(JSON.toJSONString(crystalInfos));
                //其他信息可根据配置信息自动填充
                //目前没有对接AGV，默认呼叫成功，20220811
                List<DictionaryItem> dictionaryItems = dictionaryItemService.findByThemeValueAndItemName("callAgvUrl", "url", true);
                if (dictionaryItems.size()>0){
                    if (dictionaryItems.get(0).getValue().equals("http://10.131.100.21:6602/MCS_SERVER_DATA/api/v1.0/agvAction/pull/pullAgv2Type")){
                        //taskCode = agvDispatchService.callAgv(agvCall);
                    }
                }
            } catch (Exception e) {
                //暂时先去掉验证agv错误调用处理
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                throw new RuntimeException(e.getMessage());
            }

        }


        //呼叫AGV成功后处理业务逻辑

        //长晶棒送验状态更新
        Date currentDate = new Date();
        for (String crystalNo : productionBindingTrays) {
            // 查询加工工单信息，判断是否是本站点的加工品
            PlanProcessingOrderWipStorageDto planProcessingOrderWipStorageDto = wipStorageService.selectWipStorage(crystalNo, EnumValuesFactory.WipStorageCode.送验.getKey(), true);
            //送验站点进站
            Result result = wipStorageService.outStation(planProcessingOrderWipStorageDto.getPlanProcessingOrder().getCode(), null, WipStorageStatus.已进站.getKey());
            if (result.getCode() == ResultCode.SUCCESS.getCode()) {
                LongCrystal longCrystal = longCrystalService.findByCrystalNo(crystalNo);
                if (longCrystal == null) {
                    throw new RuntimeException("在长晶棒产出记录表中未找到"+crystalNo+"晶棒信息,请检查");
                }
                longCrystal.setCrystalStatus(EnumValuesFactory.CrystalStatus.已送验.getKey());
                longCrystal.setAgvTaskCode(taskCode);
                longCrystalService.saveOrUpdate(longCrystal);

                InspectionRecord _inspectionRecord = dao.getLastCrystalNoLog(crystalNo);
                //修改记录中送验时间
                _inspectionRecord.setInspectionTime(currentDate);
                saveOrUpdate(_inspectionRecord);
            }
        }

    }


    //AGV回调
    //processingOrderCode 晶段编号
    //equipmentCode //冷却区    对应   //目标位置
    //isDeviceExistence false
    //inStation(String processingOrderCode, String equipmentCode, Boolean isDeviceExistence);
    //修改送验记录中的送验完成时间
    @Override
    public void callBack(AgvCallBackParamDto paramDto) {
        if (StringUtils.isBlank(paramDto.getTaskCode())) {
            throw new RuntimeException("请传入任务编号");
        } else if (paramDto.getTaskStatus() == null) {
            throw new RuntimeException("请传入任务状态");
        }

        if (paramDto.getTaskStatus() == 2) {//正在执行

        } else if (paramDto.getTaskStatus() == 9) {//结束
            //1根据任务编号 查询晶棒编号
            //长晶棒送验状态更新
            List<LongCrystal> longCrystals = longCrystalService.findByAgvTaskCode(paramDto.getTaskCode());
            for (LongCrystal longCrystal : longCrystals) {
                try {
                    Result result = wipStorageService.inStation(longCrystal.getCrystalNo(), "送验冷却区", false);
                    if (result.getCode() == ResultCode.SUCCESS.getCode()) {
                        //更新送验记录 送验完成时间
                        InspectionRecord inspectionRecord = dao.getLastCrystalNoLog(longCrystal.getCrystalNo());
                        inspectionRecord.setInspectionSuccessTime(new Date());
                        saveOrUpdate(inspectionRecord);
                    }
                } catch (Exception e) {
                    // TODO: AGV没上可能出现冲突 ，临时先捕捉冲突异常，不进行处理
                }
            }
        }
    }


    @Override
    public InspectionRecord findByLongCrystalId(Long id) {
        List<InspectionRecord> inspectionRecords = dao.findTop2ByLongCrystalIdOrderByIdDesc(id);
        if (inspectionRecords.size() == 0) return null;
        return inspectionRecords.get(0);
    }


    public InspectionRecord fromDto(InspectionRecordDto dto) {
        return modelMapper.map(dto, InspectionRecord.class);
    }

    public InspectionBack fromDto(InspectionBackDto dto) {
        return modelMapper.map(dto, InspectionBack.class);
    }

    @Override
    public String callAgvTest(@Valid InspectionRecordDto inspectionRecordDto) {
        String taskCode = "";
        try {
            //inspectionRecordDto.getCrystalNo().split(",");


            AgvCallDto agvCall = new AgvCallDto();
            agvCall.setKeyword(AGV_FUNCTION_KEYWORD);//关键字 根据配置中的信息固定写入  : 圆棒送验
            agvCall.setStartPoint(inspectionRecordDto.getEquipmentCode()); //起始位置编号  - 当前传入机台号
            agvCall.setFrockCode(inspectionRecordDto.getPailNum());//载具车编号
            //以下信息非必填
            agvCall.setCrystalNo(inspectionRecordDto.getCrystalNo()); //单晶编号
            //agvCall.setCrystalDetailInfo();
            //其他信息可根据配置信息自动填充
            taskCode = agvDispatchService.callAgv(agvCall);
        } catch (Exception e) {
            //暂时先去掉验证agv错误调用处理
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            taskCode = e.toString();
            throw new RuntimeException(e.getMessage());
        }

        return taskCode;
    }

    @Override
    @ServiceLogs(description = "送验绑定下发MCS")
    public Result sendMCS(InspectionRecordDto inspectionRecordDto) {
        log.info("送验绑定下发MCS -> " + JSONObject.toJSONString(inspectionRecordDto));
        List<String> productionBindingTrays = productionBindingTrayService.findCrystalNoByTrayNo(inspectionRecordDto.getPailNum());
        SybdCallDto sybdCallDto = new SybdCallDto();
        sybdCallDto.setFrockCode(inspectionRecordDto.getPailNum());
        sybdCallDto.setFrockType("5");
        //AGV所需晶棒编号
        List<String> _crystalNoArr = new ArrayList<String>();
        //agv所需晶棒详情
        List<LongCrystal> crystalInfos = new ArrayList<LongCrystal>();
        if (null != productionBindingTrays && productionBindingTrays.size() > 0) {
            for (String crystalNo : productionBindingTrays) {
                if (StringUtils.isBlank(crystalNo)) {
                    continue;
                }
                LongCrystal longCrystal = longCrystalService.findByCrystalNo(crystalNo);
                _crystalNoArr.add(crystalNo);
                crystalInfos.add(longCrystal);
            }
            //单晶编号
            sybdCallDto.setMaterialNo(StringUtils.join(_crystalNoArr.toArray(), "|"));
            sybdCallDto.setMaterialDetailInfo(JSON.toJSONString(crystalInfos));
            String data = JSONObject.toJSONString(sybdCallDto);
            String url = mcsServiceUrl + "/" + SYCBD_URL;
//            String url = "http://10.141.0.130:8806/agv/mesToMcsController/updateVehicle";
            ResponseEntity<String> responseEntity = restUtils.send(data, url, "");
            String send = responseEntity.getBody();
            JSONObject jsonObject = JSONObject.parseObject(send);
            String code = jsonObject.getString("status");
            if ("Success".equals(code)) {
                // 成功再叫AGV
                callAgv(inspectionRecordDto);
            } else {
                throw new BusinessException("送验绑定下发MCS失败：" + send + " - " + data);
            }
            return ResultGenerator.success();
        } else {
            return ResultGenerator.fail("无绑定信息，" + JSONObject.toJSONString(inspectionRecordDto));
        }
    }




    @ServiceLogs(description = "送验绑定下发MCS")
    public Result sendBindingInfoToMcs(InspectionRecordDto inspectionRecordDto) {
        log.info("送验绑定下发MCS -> " + JSONObject.toJSONString(inspectionRecordDto));
        List<String> productionBindingTrays = productionBindingTrayService.findCrystalNoByTrayNo(inspectionRecordDto.getPailNum());
//        if (productionBindingTrays.size()<2){
//            throw new RuntimeException("当前载具车尚未绑定满晶棒，请先绑定满晶棒后再点击下发信息！");
//        }

        if (productionBindingTrays.size()>=2){
            SybdCallDto sybdCallDto = new SybdCallDto();
            sybdCallDto.setFrockCode(inspectionRecordDto.getPailNum());
            sybdCallDto.setFrockType("5");
            //AGV所需晶棒编号
            List<String> _crystalNoArr = new ArrayList<String>();
            //agv所需晶棒详情
            List<LongCrystal> crystalInfos = new ArrayList<LongCrystal>();
            if (null != productionBindingTrays && productionBindingTrays.size() > 0) {
                for (String crystalNo : productionBindingTrays) {
                    if (StringUtils.isBlank(crystalNo)) {
                        continue;
                    }
                    LongCrystal longCrystal = longCrystalService.findByCrystalNo(crystalNo);

                    //将最后的晶棒绑定时间推送给mcs,使用gmtUpdate字段传递
                    longCrystal.setGmtUpdate(new Date());

                    _crystalNoArr.add(crystalNo);
                    crystalInfos.add(longCrystal);
                }
                //单晶编号
                sybdCallDto.setMaterialNo(StringUtils.join(_crystalNoArr.toArray(), "|"));
                sybdCallDto.setMaterialDetailInfo(JSON.toJSONString(crystalInfos));
                String data = JSONObject.toJSONString(sybdCallDto);
                String url = mcsServiceUrl + "/" + SYCBD_URL;
                List<DictionaryItem> dictionaryItems = dictionaryItemService.findByThemeValueAndItemName("callAgvUrl", "url", true);
                if (dictionaryItems.size()>0){
                    String callAgvUrl = mcsServiceUrl + "/" + ApiUrlConstants.MCS_CALL_AGV_API;
                    if(dictionaryItems.get(0).getValue().equals(callAgvUrl)){
//                    if (dictionaryItems.get(0).getValue().equals("http://10.141.0.130:8806/agv/taskAction/pullAgvTask")){
                        ResponseEntity<String> responseEntity = restUtils.send(data, url, "");
                        String send = responseEntity.getBody();
                        JSONObject jsonObject = JSONObject.parseObject(send);
                        String code = jsonObject.getString("status");
                        if ("Success".equals(code)) {
                        } else {
                            throw new BusinessException("送验绑定下发MCS失败：" + send + " - " + data);
                        }
                    }
                }
                return ResultGenerator.success();
            } else {
                return ResultGenerator.fail("无绑定信息，" + JSONObject.toJSONString(inspectionRecordDto));
            }
        }else {
            return ResultGenerator.success();
//            throw new RuntimeException("当前载具车尚未绑定满晶棒，请先绑定满晶棒后再点击下发信息！");
        }
    }


    /**
     * 用于人工调接口做绑定信息下发mcs，与确认绑定接口下发的区别是，人工绑定下发给mcs的绑定时间是最后一根晶棒的绑定时间，确认绑定接口下发给mcs的绑定时间取的是当前时间
     * @param inspectionRecordDto
     * @return
     */
    @ServiceLogs(description = "送验绑定下发MCS")
    public Result sendBindingInfoToMcsForManual(InspectionRecordDto inspectionRecordDto) {
        log.info("送验绑定下发MCS -> " + JSONObject.toJSONString(inspectionRecordDto));
        List<ProductionBindingTray> productionBindingTrays = productionBindingTrayDao.findByTrayNoAndCrystalNo(inspectionRecordDto.getPailNum());

        if (productionBindingTrays.size()>=2){
            SybdCallDto sybdCallDto = new SybdCallDto();
            sybdCallDto.setFrockCode(inspectionRecordDto.getPailNum());
            sybdCallDto.setFrockType("5");
            //所需晶棒编号
            List<String> _crystalNoArr = new ArrayList<String>();
            //所需晶棒详情
            List<LongCrystal> crystalInfos = new ArrayList<LongCrystal>();
            if (null != productionBindingTrays && productionBindingTrays.size() > 0) {
                for (ProductionBindingTray productionBindingTray : productionBindingTrays) {
                    if (StringUtils.isBlank(productionBindingTray.getCrystalNo())) {
                        continue;
                    }
                    LongCrystal longCrystal = longCrystalService.findByCrystalNo(productionBindingTray.getCrystalNo());


                    //将最后的晶棒绑定时间推送给mcs,使用gmtUpdate字段传递
                    List<ProductionBindingTray> lastOneByTrayNoAndCrystalNo = productionBindingTrayDao.findLastOneByTrayNoAndCrystalNo(inspectionRecordDto.getPailNum());
                    if (null != lastOneByTrayNoAndCrystalNo && lastOneByTrayNoAndCrystalNo.size()>0) {
                        longCrystal.setGmtUpdate(lastOneByTrayNoAndCrystalNo.get(0).getBindingTime());
                    }

                    _crystalNoArr.add(productionBindingTray.getCrystalNo());
                    crystalInfos.add(longCrystal);
                }
                //单晶编号
                sybdCallDto.setMaterialNo(StringUtils.join(_crystalNoArr.toArray(), "|"));
                sybdCallDto.setMaterialDetailInfo(JSON.toJSONString(crystalInfos));
                String data = JSONObject.toJSONString(sybdCallDto);
                String url = mcsServiceUrl + "/" + SYCBD_URL;
//            String url = "http://10.141.0.130:8806/agv/mesToMcsController/updateVehicle";
                ResponseEntity<String> responseEntity = restUtils.send(data, url, "");
                String send = responseEntity.getBody();
                JSONObject jsonObject = JSONObject.parseObject(send);
                String code = jsonObject.getString("status");
                if ("Success".equals(code)) {
                } else {
                    throw new BusinessException("送验绑定下发MCS失败：" + send + " - " + data);
                }
                return ResultGenerator.success();
            } else {
                return ResultGenerator.fail("无绑定信息，" + JSONObject.toJSONString(inspectionRecordDto));
            }
        }else {
            return ResultGenerator.success();
        }
    }




    private String send(String data, String url) {
        HttpHeaders headers = new HttpHeaders();
        MediaType mediaType = MediaType.parseMediaType("application/json; charset=UTF-8");
        headers.setContentType(mediaType);
        headers.add("Accept", MediaType.APPLICATION_JSON.toString());
        HttpEntity<String> httpEntity = new HttpEntity<>(data, headers);
        //使用exchange请求接口
        ResponseEntity<String> exchange = restTemplate.exchange(url, HttpMethod.POST, httpEntity, String.class);
        return exchange.getBody();
    }

    @Override
    public void busloadBuild(@Valid InspectionRecordDto inspectionRecordDto) {
        // 下发给MCS数据,下发失败需重新下发
        sendMCS(inspectionRecordDto);
    }

    @Override
    public void sendBindingInfo(InspectionRecordDto inspectionRecordDto) {
        // 下发给MCS数据,下发失败需重新下发
        sendBindingInfoToMcs(inspectionRecordDto);
    }


    @Override
    public void sendBindingInfoToMcsRg(InspectionRecordDto inspectionRecordDto) {
        // 下发给MCS数据,下发失败需重新下发
        sendBindingInfoToMcsForManual(inspectionRecordDto);
    }

    @Override
    public InspectionRecord getLastCrystalNoLog(String crystalNo) {
        return dao.getLastCrystalNoLog(crystalNo);
    }

    @Override
    @ServiceLogs(description = "呼叫取晶车log")
    public Result callTakeCrystalAgv(CallTakeCrystalAgvDto callTakeCrystalAgvDto) {
        //当前提交晶棒是否存在已呼叫取晶车
        boolean currentCallAgved = false;
        String taskCode = "";
        String specs = "";
        String callAgvMsg = "";
        CrystalDetailInfo crystalDetailInfo = new CrystalDetailInfo();
        if (callTakeCrystalAgvDto.getLongCrystal() != null) {
            if (!StringUtils.isBlank(callTakeCrystalAgvDto.getLongCrystal().getTakeCrystalAgvTaskCode())) {
                currentCallAgved = true;
                taskCode = callTakeCrystalAgvDto.getLongCrystal().getTakeCrystalAgvTaskCode();
            }
            specs = callTakeCrystalAgvDto.getLongCrystal().getSpecs();
            BeanUtil.copyBeanPropWithNullValue(crystalDetailInfo, callTakeCrystalAgvDto.getLongCrystal(),"");
        }
        if (!currentCallAgved) {
            //请求成功返回任务编号   - 任务编号用于取消agv 回调信息对照等操作
            try {
                AgvCallDto agvCall = new AgvCallDto();
                agvCall.setKeyword(EnumValuesAgv.AGVKeyword.取晶车.getValue());//关键字 根据配置中的信息固定写入  : 圆棒送验
                agvCall.setStartPoint(callTakeCrystalAgvDto.getEquipmentCode()); //起始位置编号  - 当前传入机台号
                agvCall.setTargetPoint("");
                agvCall.setSpecs(specs);
                agvCall.setLength(callTakeCrystalAgvDto.getLength());
                agvCall.setCrystalNo(callTakeCrystalAgvDto.getCrystalNo());
                agvCall.setCrystalDetailInfo(JSONObject.toJSONString(crystalDetailInfo));
                //其他信息可根据配置信息自动填充
                taskCode = agvDispatchService.callAgv(agvCall);
                callAgvMsg = "成功！";
            } catch (Exception e) {
                //验证agv错误调用处理
                callAgvMsg = e.getMessage();
            }
        }
        callTakeCrystalAgvDto.getLongCrystal().setTakeCrystalAgvTaskMsg(callAgvMsg);
        callTakeCrystalAgvDto.getLongCrystal().setHasCall(callTakeCrystalAgvDto.getIsAuto());
        callTakeCrystalAgvDto.getLongCrystal().setTakeCrystalAgvTaskCode(taskCode);
        callTakeCrystalAgvDto.getLongCrystal().setTakeCrystalTime(new Date());
        longCrystalService.saveOrUpdate(callTakeCrystalAgvDto.getLongCrystal());

        return ResultGenerator.success();
    }

    @Override
    @ServiceLogs(description = "自动取晶任务回调送验呼叫AGV")
    public void callTakeCrystalAgvBack(AgvCallBackParamDto paramDto) {
        if (StringUtils.isBlank(paramDto.getTaskCode())) {
            throw new RuntimeException("请传入任务编号");
        } else if (paramDto.getTaskStatus() == null) {
            throw new RuntimeException("请传入任务状态");
        }

        //取晶任务状态更新
        List<LongCrystal> longCrystals = longCrystalService.findByTakeCrystalAgvTaskCode(paramDto.getTaskCode());
        for (LongCrystal longCrystal : longCrystals) {
            longCrystal.setCrystalAgvTaskState(paramDto.getTaskStatus());
            longCrystalService.saveOrUpdate(longCrystal);
        }
    }

}