package com.shkj.wcs.plc;

import com.shkj.common.constant.RedisConstant;
import com.shkj.common.core.domain.Result;
import com.shkj.common.enums.BusinessType;
import com.shkj.plc.sdk.device.PlcOperate;
import com.shkj.system.service.ISysParameterService;
import com.shkj.wcs.bo.WcsPlcConnectQueryBo;
import com.shkj.wcs.domain.WcsPlcConnect;
import com.shkj.wcs.domain.WcsPlcProperty;
import com.shkj.wcs.mapper.WcsPlcConnectMapper;
import com.shkj.wcs.service.IWcsPlcConnectService;
import com.shkj.wcs.service.IWcsPlcPropertyService;
import com.shkj.wcs.third.rcs.RCSUtil;
import com.shkj.wcs.third.workbinWcs.WCSUtil;
import com.shkj.wcs.third.workbinWcs.dto.WCSQueryTaskStatusBody;
import com.shkj.wcs.third.workbinWcs.dto.WcsIncomingTaskRequestBody;
import com.shkj.wcs.vo.TaskStatusBody;
import com.shkj.wcs.vo.WcsPlcConnectVo;
import com.shkj.wcs.vo.WcsResponseVo;
import com.shkj.wms.enums.BusinTaskTypeEnum;
import com.shkj.wms.enums.TaskTypeEnum;
import com.shkj.wms.utils.JsonUtil;
import com.shkj.wms.vo.PlanOrderLocationVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.EnableScheduling;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.*;

import com.shkj.plc.sdk.device.PLCReadAndWrite;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;


@Slf4j
@Service("PlcEventTask")
@EnableScheduling
public class PlcEventTask {

    @Autowired
    IWcsPlcConnectService iWcsPlcConnectService;

    @Resource
    RedisTemplate redisTemplate;

    @Autowired
    RCSUtil rcsUtil;

    @Autowired
    IWcsPlcPropertyService iWcsPlcPropertyService;

    @Autowired
    ISysParameterService isysParameterService;

    @Resource
    WcsPlcConnectMapper wcsPlcConnectMapper;


    @Autowired
    PlcInit plcInit;

    @Autowired
    WCSUtil wcsUtil;

    @Scheduled(fixedDelay = 5000)
    public void init() {
        //查询需要连接的PLC,初始化连接对象
        List<WcsPlcConnectVo> plcList =(List<WcsPlcConnectVo>) redisTemplate.opsForValue().get(RedisConstant.redisPlcListConnect);
        if (plcList == null || plcList.size()==0) {
            plcList = iWcsPlcConnectService.selectWcsPlcConnectList(new WcsPlcConnect().setIsActive("1"));
            redisTemplate.opsForValue().set(RedisConstant.redisPlcListConnect,plcList);
        }

        for (WcsPlcConnectVo conn : plcList) {
            if (conn.getPlcIp().contains("155.180")) {
                plcTask(plcInit.getPlcOperate_stk(), conn, conn.getPointTables());
            }

            if (conn.getPlcIp().contains("155.170")) {
                plcTask(plcInit.getPlcOperate_dps(), conn, conn.getPointTables());
            }
        }
    }


    //输送线心跳
    @Scheduled(fixedDelay = 4000)
    public void writePlcheartbeatDps() {
        //根据连接的plcId获取属性
        PlcOperate plcOperate = plcInit.getPlcOperate_dps();
        PLCReadAndWrite plcReadAndWrite = new PLCReadAndWrite();
        Map<String, Object> readPointMap = new HashMap<>();
        String heartbeat = "DB5100";
        readPointMap.put(heartbeat, "Boolean");
        Map<String, Object> pointMap = plcReadAndWrite.readPlcData(plcOperate, JsonUtil.toJSONString(readPointMap));

        //读取心跳，并判断是写入true还是false;
        Boolean heartbeatV = false;

        if (pointMap.containsKey(heartbeat)) {
            heartbeatV = Boolean.valueOf(pointMap.get(heartbeat).toString());
        }
        heartbeatV = (heartbeatV == true) ? false : true;
        Map<String, Object> writeHbMap = new HashMap<>(1);
        writeHbMap.put("Boolean", heartbeatV);
        Map<String, Object> allHbMap = new HashMap<>(1);
        allHbMap.put(heartbeat, writeHbMap);
        Boolean heartType = plcReadAndWrite.execWrite(plcOperate, JsonUtil.toJSONString(allHbMap));
        if (!heartType) {
            log.info("dps心跳写入失败，重连服务器");
            plcInit.connect();
        }
    }

    //堆垛机心跳
    //@Scheduled(fixedDelay = 4000)
    public void writePlcheartbeatStk() {
        //根据连接的plcId获取属性
        PlcOperate plcOperate = plcInit.getPlcOperate_stk();
        PLCReadAndWrite plcReadAndWrite = new PLCReadAndWrite();
        Map<String, Object> readPointMap = new HashMap<>();
        String heartbeat = "DB20.0.4";
        readPointMap.put(heartbeat, "Boolean");
        Map<String, Object> pointMap = plcReadAndWrite.readPlcData(plcOperate, JsonUtil.toJSONString(readPointMap));

        //读取心跳，并判断是写入true还是false;
        Boolean heartbeatV = false;

        if (pointMap.containsKey(heartbeat)) {
            heartbeatV = Boolean.valueOf(pointMap.get(heartbeat).toString());
        }
        heartbeatV = (heartbeatV == true) ? false : true;
        Map<String, Object> writeHbMap = new HashMap<>(1);
        writeHbMap.put("Boolean", heartbeatV);
        Map<String, Object> allHbMap = new HashMap<>(1);
        allHbMap.put(heartbeat, writeHbMap);
        Boolean heartType = plcReadAndWrite.execWrite(plcOperate, JsonUtil.toJSONString(allHbMap));
        if (!heartType) {
            log.info("stk心跳写入失败，重连服务器");
            plcInit.connect();
        }
    }

    public void plcTask(PlcOperate plcOperate, WcsPlcConnectVo conn, String pointTables) {

        Long plcId = conn.getId();
        //根据连接的plcId获取属性
        PLCReadAndWrite plcReadAndWrite = new PLCReadAndWrite();
        Map<String, Object> pointMap = plcReadAndWrite.readPlcData(plcOperate, pointTables);
        //     log.info("连接的IP:"+conn.getPlcIp()+":设备："+conn.getConnectName()+"   读取的点位内容："+pointMap);

        List<WcsPlcProperty> propertyList = (List<WcsPlcProperty>) redisTemplate.opsForValue().get(RedisConstant.redisPlcProperty + plcId);
        if (propertyList == null || propertyList.size() == 0) {
            propertyList = iWcsPlcPropertyService.getWcsPlcPropertyByPlcId(plcId);
        }

        // 设备类型：2输送线  1 堆垛机
        switch (conn.getDevType()) {
            //输送线
            case "2":
                dpsRealTimeTask(propertyList, pointMap, plcReadAndWrite, plcOperate);
                break;
            default:
                log.info("无匹配的设备类型");
                break;
        }
    }

    public void dpsRealTimeTask(List<WcsPlcProperty> propertyList, Map<String, Object> pointMap, PLCReadAndWrite plcReadAndWrite, PlcOperate plcOperate) {
        try {
            /**
             * 请求入库
             */
            //BCR01请求序列号
            String reqInSeria = "";

            //BCR01条码
            String reqInBarcod = "";
            //BCR01条码数据类型

            //BCR01外形检测
            String reqInLength = "";

            //请求入库返回序列号
            String reqInCfmSeria = "";
            String reqInCfmSeriaVt = "";

            //请求入库返回条码
            String reqInCfmBarcod= "";
            String reqInCfmBarcodVt= "";

            //返回去向
            String reqInDest = "";
            String reqInDestVt= "";

            /**
             * 空托
             */
            //空托申请
            String reqEmpty = "";

            //空托确认
            String reqCfm = "";
            String reqCfmVt = "";

            /**
             * 出口上报
             */
            //出口上报请求序列号
            String rptOutSeria = "";

            //出口上报条码
            String rptOutBarcod = "";

            //出口上报确认序列号
            String rptOutCfmSeria = "";
            String rptOutCfmSeriaVt = "";

            //出口上报条码确认
            String rptOutCfmBarcod= "";
            String rptOutCfmBarcodVt= "";

            //出口上报返回信息
            String retOut = "";
            String retOutVt= "";

            /**
             * 出入库切换
             */
            //出入库切换
            String inOutSwit = "";

            //出入库切换返回
            String retInOutSwit = "";
            String retInOutSwitVt = "";

            /**
             * 叠盘机
             */
            //叠盘机完成
            String stk = "";

            //叠盘机返回
            String retStk = "";
            String retStkVt = "";


            for (WcsPlcProperty plcProperty : propertyList) {
                String pointType = plcProperty.getPointType();
                //请求分配
                if (pointType.equals("reqInSeria")) {
                    reqInSeria = plcProperty.getAddress();
                }  else if (pointType.equals("reqInBarcod")) {
                    reqInBarcod = plcProperty.getAddress();
                }  else if (pointType.equals("reqInLength")) {
                    reqInLength = plcProperty.getAddress();
                    reqInLength = plcProperty.getPointType();
                }  else if (pointType.equals("reqInCfmSeria")) {
                    reqInCfmSeria = plcProperty.getAddress();
                    reqInCfmSeriaVt = plcProperty.getPointType();
                }  else if (pointType.equals("reqInCfmBarcod")) {
                    reqInCfmBarcod = plcProperty.getAddress();
                    reqInCfmBarcodVt = plcProperty.getPointType();
                }  else if (pointType.equals("reqInDest")) {
                    reqInDest = plcProperty.getAddress();
                    reqInDestVt = plcProperty.getPointType();

                }  else if (pointType.equals("reqEmpty")) {
                    reqEmpty = plcProperty.getAddress();
                }  else if (pointType.equals("reqCfm")) {
                    reqCfm = plcProperty.getAddress();
                    reqCfmVt = plcProperty.getPointType();
                }  else if (pointType.equals("rptOutSeria")) {
                    rptOutSeria = plcProperty.getAddress();
                }  else if (pointType.equals("rptOutBarcod")) {
                    rptOutBarcod = plcProperty.getAddress();
                }  else if (pointType.equals("rptOutCfmSeria")) {
                    rptOutCfmSeria = plcProperty.getAddress();
                    rptOutCfmSeriaVt = plcProperty.getPointType();
                }  else if (pointType.equals("rptOutCfmBarcod")) {
                    rptOutCfmBarcod = plcProperty.getAddress();
                    rptOutCfmBarcodVt = plcProperty.getPointType();
                }  else if (pointType.equals("retOut")) {
                    retOut = plcProperty.getAddress();
                    retOutVt = plcProperty.getPointType();
                }  else if (pointType.equals("inOutSwit")) {
                    inOutSwit = plcProperty.getAddress();
                }  else if (pointType.equals("retInOutSwit")) {
                    retInOutSwit = plcProperty.getAddress();
                    retInOutSwitVt = plcProperty.getPointType();
                }

            }
            //扫码处入库申请
            if (pointMap.containsKey(reqInSeria) && Boolean.valueOf(pointMap.get(reqInSeria).toString())) {
                //读取请求序列号内容
                Integer bCR01SeriaV = (Integer) pointMap.get(reqInSeria);
                //读取托盘条码内容
                String barcodeValueOne = pointMap.get(reqInBarcod).toString();
                log.info("扫码处入库申请时，读取的条码内容：" + barcodeValueOne);
                //根据托盘条码返回正在执行的任务号
                WcsIncomingTaskRequestBody body = new WcsIncomingTaskRequestBody();
                body.setStation("");
                body.setTaskType(TaskTypeEnum.In.getValue());
                body.setBussinessType(BusinTaskTypeEnum.stockIn.getValue());
                body.setTrayCode(barcodeValueOne);
                body.setCreateDt(new Date().toString());
                //调用agv接口查询库区状态
                Object[] areaStatus = {};
                body.setAreaStatus(areaStatus);
                WcsResponseVo vo = wcsUtil.wcsIncomingTaskRequest(body);
                log.info("扫码处入库申请wz-wcs返回：" + vo.getHeader());
                Map<String, Object> allMap = new HashMap<>(1);
                Map<String, Integer> seriaMap = new HashMap<>(1);
                seriaMap.put(reqInCfmSeriaVt,bCR01SeriaV );
                allMap.put(reqInCfmSeria, seriaMap);

                Map<String, String> barcodMap = new HashMap<>(1);
                barcodMap.put(reqInCfmBarcodVt, barcodeValueOne);
                allMap.put(reqInCfmBarcod, barcodMap);
                //成功直行 失败回退
                if (Result.isOk(vo.getHeader().getMsgCode())) {
                    Map<String, Integer> destMap = new HashMap<>(1);
                    destMap.put(reqInDestVt, 1);
                    allMap.put(reqInDest, destMap);
                } else {
                    Map<String, Integer> destMap = new HashMap<>(1);
                    destMap.put(reqInDestVt, 2);
                    allMap.put(reqInDest, destMap);
                }
                String allMapJson = JsonUtil.toJSONString(allMap);
                log.info("扫码处入库申请时，给输送线写命令数据：{}",allMapJson);
                Boolean reqInBoolean = plcReadAndWrite.execWrite(plcOperate, allMapJson);
                log.info("扫码处入库申请时，写入的命令返回结果："+reqInBoolean.toString());
            }
            //空托盘申请
            if (pointMap.containsKey(reqEmpty) && Boolean.valueOf(pointMap.get(reqEmpty).toString())) {
                WcsIncomingTaskRequestBody body = new WcsIncomingTaskRequestBody();
                body.setStation("空托处");
                body.setTaskType(TaskTypeEnum.Out.getValue());
                body.setBussinessType(BusinTaskTypeEnum.stockOut.getValue());
                body.setCreateDt(new Date().toString());
                //调用agv接口查询库区状态
                Object[] areaStatus = {};
                body.setAreaStatus(areaStatus);
                WcsResponseVo vo = wcsUtil.wcsIncomingTaskRequest(body);
                log.info("空托申请wz-wcs返回：" + vo.getHeader());
                Map<String, Object> allMap = new HashMap<>(1);
                Map<String, Integer> reqMap = new HashMap<>(1);

                if (Result.isOk(vo.getHeader().getMsgCode())) {
                    reqMap.put(retOutVt,1);
                } else {
                    reqMap.put(retOutVt,0);
                }
                allMap.put(retOut, reqMap);
                String allMapJson = JsonUtil.toJSONString(allMap);
                log.info("空托申请时，给输送线写命令数据：{}",allMapJson);
                Boolean bCR01Boolean = plcReadAndWrite.execWrite(plcOperate, allMapJson);
                log.info("空托申请时，写入的命令返回结果："+bCR01Boolean.toString());
            }

            //实盘出口上报
            if (pointMap.containsKey(rptOutSeria) && Boolean.valueOf(pointMap.get(rptOutSeria).toString())) {
                //读取序列号
                Integer outSeria = (Integer) pointMap.get(rptOutSeria);
                //读取托盘条码内容
                String barcodeValueOne = pointMap.get(rptOutBarcod).toString();
                log.info("请求入库时，读取的条码内容：" + barcodeValueOne);
                //调用wz-wcs接口
                WcsIncomingTaskRequestBody body = new WcsIncomingTaskRequestBody();
                body.setStation("出口上报处");
                body.setTaskType(TaskTypeEnum.In.getValue());
                body.setBussinessType(BusinTaskTypeEnum.stockIn.getValue());
                body.setTrayCode(barcodeValueOne);
                body.setCreateDt(new Date().toString());
                //调用agv接口查询库区状态
                Object[] areaStatus = {};
                body.setAreaStatus(areaStatus);
                WcsResponseVo vo = wcsUtil.wcsIncomingTaskRequest(body);
                log.info("agv扫码处申请wz-wcs返回：" + vo.getHeader());
                Map<String, Object> allMap = new HashMap<>(1);
                Map<String, Integer> seriaMap = new HashMap<>(1);
                seriaMap.put(rptOutCfmSeriaVt,outSeria );
                allMap.put(rptOutCfmSeria, seriaMap);

                Map<String, String> barcodMap = new HashMap<>(1);
                barcodMap.put(rptOutCfmBarcodVt, barcodeValueOne);
                allMap.put(rptOutCfmBarcod, barcodMap);
                Map<String, Integer> reqMap = new HashMap<>(1);

                if (Result.isOk(vo.getHeader().getMsgCode())) {
                    reqMap.put(reqCfmVt,1);
                } else {
                    reqMap.put(reqCfmVt,0);
                }
                allMap.put(reqCfm, reqMap);
                String allMapJson = JsonUtil.toJSONString(allMap);
                log.info("出口上报时，给输送线写命令数据：{}",allMapJson);
                Boolean rptOutBoolean = plcReadAndWrite.execWrite(plcOperate, allMapJson);
                log.info("出口上报时，写入的命令返回结果："+rptOutBoolean.toString());
            }

            //出入库切换
            if (pointMap.containsKey(inOutSwit) && Boolean.valueOf(pointMap.get(inOutSwit).toString())) {
                WCSQueryTaskStatusBody body = new WCSQueryTaskStatusBody();
                body.setDestination("叠盘机");
                body.setTaskType("1");
                body.setTrayType("2");
                WcsResponseVo<TaskStatusBody> vo = wcsUtil.queryTaskStatus(body);
                log.info("扫码处入库申请wz-wcs返回：" + vo.getHeader());
                Map<String, Object> allMap = new HashMap<>(1);
                Map<String, Integer> reqMap = new HashMap<>(1);
                if (Result.isOk(vo.getHeader().getMsgCode())) {
                    int taskCount = vo.getBody().get(0).getTaskCount();
                    if (taskCount == 0){
                        reqMap.put(retInOutSwitVt,2);
                    }else {
                        reqMap.put(retInOutSwitVt,1);
                    }
                } else {
                    reqMap.put(retInOutSwitVt,1);
                }
                allMap.put(retInOutSwit, reqMap);
                String allMapJson = JsonUtil.toJSONString(allMap);
                log.info("出入库切换时，给输送线写命令数据：{}",allMapJson);
                Boolean inOutSwitBoolean = plcReadAndWrite.execWrite(plcOperate, allMapJson);
                log.info("出入库切换时，写入的命令返回结果："+inOutSwitBoolean.toString());
            }

        } catch (Exception e) {
            log.error("dpsRealTimeTask:" + e.getMessage());
        }
    }

}
