package com.shkj.wcs.third.stacker;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.shkj.common.constant.RedisConstant;
import com.shkj.common.core.domain.Result;
import com.shkj.common.utils.DateUtils;
import com.shkj.plc.sdk.device.PLCReadAndWrite;
import com.shkj.plc.sdk.device.PlcHelper;
import com.shkj.plc.sdk.device.PlcOperate;
import com.shkj.wcs.bo.WcsPlcConnectQueryBo;
import com.shkj.wcs.domain.WcsPlcProperty;
import com.shkj.wcs.mapper.WcsPlcConnectMapper;
import com.shkj.wcs.plc.PlcInit;
import com.shkj.wcs.service.IWcsPlcConnectService;
import com.shkj.wcs.service.IWcsPlcPropertyService;
import com.shkj.wcs.vo.WcsPlcConnectVo;
import com.shkj.wms.bo.STKMoveBo;
import com.shkj.wms.domain.BusinStockInv;
import com.shkj.wms.domain.SysThirdExceptionRequest;
import com.shkj.wms.enums.InvStatusEnum;
import com.shkj.wms.enums.PlcPropertyEnum;
import com.shkj.wms.enums.ThirdApiStatusEnum;
import com.shkj.wms.service.ISysThirdExceptionRequestService;
import com.shkj.wms.utils.JsonUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.ejb.access.AbstractRemoteSlsbInvokerInterceptor;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Slf4j
@Component
public class StkCallUtil {

    @Resource
    RedisTemplate redisTemplate;

    @Autowired
    IWcsPlcConnectService iWcsPlcConnectService;

    @Autowired
    IWcsPlcPropertyService iWcsPlcPropertyService;

    @Autowired
    PLCReadAndWrite plcReadAndWrite;

    @Resource
    WcsPlcConnectMapper wcsPlcConnectMapper;

    @Autowired
    ISysThirdExceptionRequestService sysThirdExceptionRequestService;

    @Autowired
    PlcInit plcInit;

    /**
     * 堆垛机出库命令
     *
     * @param stkMoveBo
     * @return
     */
    public Result<Boolean> outTask(STKMoveBo stkMoveBo) throws InterruptedException {
        //下发任务时，先查询是否有正在执行的入库任务，如果有，则不下发出库任务
        Object taskInId = redisTemplate.opsForValue().get(RedisConstant.redisTaskIn);
        if (taskInId !=null ){
            log.info("有入库任务在执行，无法下发出库任务:"+taskInId);
            return Result.err().msg("有入库任务在执行，无法下发出库任务");
        }

        Object taskOutId = redisTemplate.opsForValue().get(RedisConstant.redisTaskOut);
        if (taskOutId !=null ){
            log.info("有出库任务在执行，无法下发出库任务:"+taskOutId);
            return Result.err().msg("有出库任务在执行，无法下发出库任");
        }
        Long taskId = stkMoveBo.getTaskId();
        SysThirdExceptionRequest one = sysThirdExceptionRequestService.getOneByOrderNo(taskId.toString());
        if (one != null){
            if (!one.getCode().equals(taskId.toString())){
                log.info("有更早未执行的任务，排队执行:"+JsonUtil.toJSONString(one));
                 return Result.err().msg("有更早未执行的任务，排队执行");
            }
        }

        String fromLayer = stkMoveBo.getFromLayer();
        String fromColumn = stkMoveBo.getFromColumn();
        String fromRow = stkMoveBo.getFromRow();
        log.info(taskId +"出库对应的排层列："+fromRow+fromLayer+fromColumn);
        //获取堆垛机
        WcsPlcConnectQueryBo plcConnect = new WcsPlcConnectQueryBo();
        plcConnect.setDevType("1");
        WcsPlcConnectVo wcsPlcConnectVo = wcsPlcConnectMapper.selectPlcConnectBydevType(plcConnect);
        Long stkPlcId = wcsPlcConnectVo.getId();
        String pointTables = wcsPlcConnectVo.getPointTables();

        PlcOperate stkOperate = plcInit.getPlcOperateByIp(wcsPlcConnectVo.getPlcIp());
        Map<String, Object> stkPointMap = plcReadAndWrite.readPlcData(stkOperate, pointTables);

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

        //获取输送线
        WcsPlcConnectQueryBo plcDpsConnect = new WcsPlcConnectQueryBo();
        plcDpsConnect.setDevType("2");
        WcsPlcConnectVo dpsPlcConnectVo = wcsPlcConnectMapper.selectPlcConnectBydevType(plcDpsConnect);
        Long dpsPlcId = dpsPlcConnectVo.getId();
        String dpsPointTables = dpsPlcConnectVo.getPointTables();
        PlcOperate dpsOperate = plcInit.getPlcOperateByIp(dpsPlcConnectVo.getPlcIp());
        Map<String, Object> dpsPointMap = plcReadAndWrite.readPlcData(dpsOperate, dpsPointTables);

        List<WcsPlcProperty> dpsPropertyList = iWcsPlcPropertyService.getWcsPlcPropertyByPlcId(dpsPlcId);
        String oneDpsidle="";
        String twoDpsidle="";
        String oneDpsidleV="";
        String twoDpsidleV="";
        for (WcsPlcProperty dpsProperty : dpsPropertyList) {
            //1楼是否允许出库
            if (dpsProperty.getPointType().equals("oneOut")) {
                oneDpsidle = dpsProperty.getAddress();
            }

            //2楼是否允许出库
            if (dpsProperty.getPointType().equals("twoOut")) {
                twoDpsidle = dpsProperty.getAddress();
            }
        }

        if (dpsPointMap.containsKey(oneDpsidle)){
            oneDpsidleV = dpsPointMap.get(oneDpsidle).toString();
        }

        if (dpsPointMap.containsKey(twoDpsidle)){
            twoDpsidleV = dpsPointMap.get(twoDpsidle).toString();
        }

        log.info(taskId+"1楼是否允许出库:："+oneDpsidle+" 出库的值："+oneDpsidleV);
        log.info(taskId+"2楼是否允许出库:："+twoDpsidle+" 出库的值："+twoDpsidleV);
        //出库的站台
        Integer layer =stkMoveBo.getLayer();
        if (layer==1){
            //false不允许出库
            if (!Boolean.valueOf(oneDpsidleV)){
                String msg ="出库楼层是1楼，输送线繁忙，不允许出库";
                log.info(msg);
                return Result.err().msg(msg);
            }
        }else if(layer == 2){
            if (!Boolean.valueOf(twoDpsidleV)){
                String msg ="出库楼层是2楼，输送线繁忙，不允许出库";
                log.info(msg);
                return Result.err().msg(msg);
            }
        }else {
            log.info("出库任务未匹配到楼层");
            return Result.err().msg("未匹配到楼层，不允许出库");
        }

        String plcTaskId = "",taskIdvalueType = "",plcToRow = "",toRowValueType = "",plcToColumn = "",toColumnValueType = "",plcToLayer = "",toLayerValueType = "";
        String plcFromRow = "";
        String FromRowValueType="";
        String plcFromColumn = "";
        String FromColumnValueType = "";
        String plcFromLayer = "";
        String FromLayerValueType="";
        String plcOrderType = "";
        String plcOrderTypeValue = "";

        //堆垛机完成状态
        String finishPoint="";
        String finishPointVT="";

        //站台
        String plcPlatform="";
        String plcPlatformValueType="";

        String stkAutoManual="", stkGround="",stkidle="", stkRun="";
        for (WcsPlcProperty stkProperty : propertyList) {
            //获取要堆垛机要写入的点位
            if (stkProperty.getPointType().equals("101")) {
                plcTaskId = stkProperty.getAddress();
                taskIdvalueType = stkProperty.getValueType();
            } else if (stkProperty.getPointType().equals("104")) {
                plcFromRow = stkProperty.getAddress();
                FromRowValueType = stkProperty.getValueType();
            } else if (stkProperty.getPointType().equals("105")) {
                plcFromColumn = stkProperty.getAddress();
                FromColumnValueType=stkProperty.getValueType();
            } else if (stkProperty.getPointType().equals("106")) {
                plcFromLayer = stkProperty.getAddress();
                FromLayerValueType=stkProperty.getValueType();
            } else if (stkProperty.getPointType().equals("107")) {
                plcPlatform = stkProperty.getAddress();
                plcPlatformValueType = stkProperty.getValueType();
            } else if (stkProperty.getPointType().equals("10")) {
                //等于1时堆垛机自动，等于0时堆垛机手动
                stkAutoManual = stkProperty.getAddress();
            }else if (stkProperty.getPointType().equals("11")) {
                //等于1时地面柜自动，等于0时地面柜手动
                stkGround = stkProperty.getAddress();
            }else if (stkProperty.getPointType().equals("12")) {
                //等于1时堆垛机空闲，等于0时堆垛机正忙
                stkidle = stkProperty.getAddress();
            } else if (stkProperty.getPointType().equals("102")) {
                plcOrderType = stkProperty.getAddress();
                plcOrderTypeValue=stkProperty.getValueType();
            } else if (stkProperty.getPointType().equals("13")) {
                //等于1时堆垛机已激活（运行）
                stkRun = stkProperty.getAddress();
            }else if (stkProperty.getPointType().equals("4")) {
                finishPoint = stkProperty.getAddress();
                finishPointVT =stkProperty.getValueType();
            }
        }

        Thread.sleep(2000);

        Boolean stkRunV = false;
        if (stkPointMap.containsKey(stkRun)) {
            stkRunV = Boolean.valueOf(stkPointMap.get(stkRun).toString());
        }
        log.info("堆垛机运行状态："+stkRunV);
        if (!stkRunV){
            log.info("堆垛机尚未运行："+stkRunV);
            return Result.err().msg("堆垛机尚未运行");
        }


        Boolean stkAutoManualV=false;
        if (stkPointMap.containsKey(stkAutoManual)) {
            stkAutoManualV = Boolean.valueOf(stkPointMap.get(stkAutoManual).toString());
        }
        log.info("堆垛机自动状态："+stkAutoManualV);
        if(!stkAutoManualV ){
            log.info("堆垛机手动状态："+stkAutoManualV);
            return Result.err().msg("堆垛机手动状态");
        }

        Boolean stkGroundV= false;
        if (stkPointMap.containsKey(stkGround)) {
            stkGroundV = Boolean.valueOf(stkPointMap.get(stkGround).toString());
        }
        log.info("地面柜自动状态："+stkGroundV);
        if(!stkGroundV){
            log.info("堆垛机地面柜手动状态："+stkGroundV);
            return Result.err().msg("堆垛机地面柜手动状态");
        }

        Boolean stkidleV = false;
        if (stkPointMap.containsKey(stkidle)) {
            stkidleV = Boolean.valueOf(stkPointMap.get(stkidle).toString());
        }
        if(!stkidleV){
            log.info("堆垛机繁忙："+stkidleV);
            return Result.err().msg("堆垛机繁忙");
        }

        if((!Boolean.valueOf(oneDpsidleV) || !Boolean.valueOf(twoDpsidleV))   && !stkidleV){
            return Result.err().msg("出库状态与堆垛机的状态都不可出库");
        }else{
            log.info("出库状态与堆垛机的状态可出库one: "+Boolean.valueOf(oneDpsidleV)+" two:"+twoDpsidleV+" --"+stkidleV);
        }
        //给堆垛机写命令
        Map<String, Object> allMap = new HashMap<>(1);
        Map<String, Object> plcTaskIdMap = new HashMap<>(1);
        plcTaskIdMap.put(taskIdvalueType, taskId);
        allMap.put(plcTaskId, plcTaskIdMap);

        //出库目标站台
        Map<String, Object> plcPlatformMap = new HashMap<>(1);
        plcPlatformMap.put(plcPlatformValueType,layer);
        allMap.put(plcPlatform,plcPlatformMap);

        Map<String, Object> plcOrderTypeMap = new HashMap<>(1);
        plcOrderTypeMap.put(plcOrderTypeValue, 2);
        allMap.put(plcOrderType, plcOrderTypeMap);
        Map<String, Object> plcFromRowMap = new HashMap<>(1);
        plcFromRowMap.put(FromRowValueType, fromRow);
        allMap.put(plcFromRow, plcFromRowMap);
        Map<String, Object> plcFromColumnMap = new HashMap<>(1);
        plcFromColumnMap.put(FromColumnValueType, fromColumn);
        allMap.put(plcFromColumn, plcFromColumnMap);
        Map<String, Object> plcFromLayerMap = new HashMap<>(1);
        plcFromLayerMap.put(FromLayerValueType, fromLayer);
        allMap.put(plcFromLayer, plcFromLayerMap);

        //堆垛机完成入库状态
        Map<String, Object> finishPointMap = new HashMap<>(1);
        finishPointMap.put(finishPointVT, 0);
        allMap.put(finishPoint, finishPointMap);
        PLCReadAndWrite plcReadAndWrite = new PLCReadAndWrite();
        if ( plcReadAndWrite.execWrite(stkOperate, JsonUtil.toJSONString(allMap)) ){
            redisTemplate.opsForValue().set(RedisConstant.redisTaskTime, DateUtils.getNowDate());
            redisTemplate.opsForValue().set(RedisConstant.redisTaskOut, taskId);
            return Result.ok();
        } else {
            log.info(one.getTaskId()+"堆垛机下发命令失败");
            return Result.err();
        }
    }

    /**
     * 货位调整
     * @param stkMoveBo
     * @return
     */
    public Result<Boolean> locationAdjustment(STKMoveBo stkMoveBo) {
        String fromLayer = stkMoveBo.getFromLayer();
        String fromColumn = stkMoveBo.getFromColumn();
        String fromRow = stkMoveBo.getFromRow();

        String toLayer = stkMoveBo.getToLayer();
        String toColumn = stkMoveBo.getToColumn();
        String toRow = stkMoveBo.getToRow();

        //启动设备
        String plcStartEq = "";
        String plcStartEqValueType = "";

        //获取堆垛机
        WcsPlcConnectQueryBo plcConnect = new WcsPlcConnectQueryBo();
        plcConnect.setDevType("1");
        WcsPlcConnectVo wcsPlcConnectVo = wcsPlcConnectMapper.selectPlcConnectBydevType(plcConnect);
        Long stkPlcId = wcsPlcConnectVo.getId();
        String pointTables = wcsPlcConnectVo.getPointTables();
        PlcOperate stkOperate = plcInit.getPlcOperateByIp(wcsPlcConnectVo.getPlcIp());

        Map<String, Object> pointMap = plcReadAndWrite.readPlcData(stkOperate, pointTables);

        List<WcsPlcProperty> propertyList = iWcsPlcPropertyService.getWcsPlcPropertyByPlcId(stkPlcId);

        String plcTaskId = "",taskIdvalueType = "", plcToRow = "",toRowValueType = "", plcToColumn = "",toColumnValueType = "",plcToLayer = "",toLayerValueType = "";

        String plcfromRow ="", fromRowValueType = "",plcfromColumn ="",fromColumnValueType="",plcfromLayer = "",fromLayerValueType="";

        String stkAutoManual="", stkGround="",stkidle="",stkRun="";

        for (WcsPlcProperty stkProperty : propertyList) {
            //获取要堆垛机要写入的点位
            if (stkProperty.getPointType().equals("101")) {
                plcTaskId = stkProperty.getAddress();
                taskIdvalueType = stkProperty.getValueType();
            } else if (stkProperty.getPointType().equals("108")) {
                plcToRow = stkProperty.getAddress();
                toRowValueType = stkProperty.getValueType();
            } else if (stkProperty.getPointType().equals("109")) {
                plcToColumn = stkProperty.getAddress();
                toColumnValueType = stkProperty.getValueType();
            } else if (stkProperty.getPointType().equals("110")) {
                plcToLayer = stkProperty.getAddress();
                toLayerValueType = stkProperty.getValueType();
            } else if (stkProperty.getPointType().equals("104")) {
                plcfromRow = stkProperty.getAddress();
                fromRowValueType=stkProperty.getValueType();
            } else if (stkProperty.getPointType().equals("105")) {
                plcfromColumn = stkProperty.getAddress();
                fromColumnValueType=stkProperty.getValueType();
            } else if (stkProperty.getPointType().equals("106")) {
                plcfromLayer = stkProperty.getAddress();
                fromLayerValueType=stkProperty.getValueType();
            }else if (stkProperty.getPointType().equals("10")) {
                //等于1时堆垛机自动，等于0时堆垛机手动
                stkAutoManual = stkProperty.getAddress();
            }else if (stkProperty.getPointType().equals("11")) {
                //等于1时地面柜自动，等于0时地面柜手动
                stkGround = stkProperty.getAddress();
            }else if (stkProperty.getPointType().equals("12")) {
                //等于1时堆垛机空闲，等于0时堆垛机正忙
                stkidle = stkProperty.getAddress();
            }else if (stkProperty.getPointType().equals("13")) {
                //等于1时堆垛机已激活（运行）
                stkRun = stkProperty.getAddress();
            }else if (stkProperty.getPointType().equals(PlcPropertyEnum.twentythree.getValue())){
                plcStartEq=stkProperty.getAddress();
                plcStartEqValueType=stkProperty.getValueType();
            }
        }

        Boolean stkAutoManualV= false;
        if (pointMap.containsKey(stkAutoManual)) {
            stkAutoManualV = Boolean.valueOf(pointMap.get(stkAutoManual).toString());
        }
        Boolean stkGroundV= false;
        if (pointMap.containsKey(stkGround)) {
            stkGroundV = Boolean.valueOf(pointMap.get(stkGround).toString());
        }
        Boolean stkidleV = false;
        if (pointMap.containsKey(stkidle)) {
            stkidleV = Boolean.valueOf(pointMap.get(stkidle).toString());
        }

        Boolean stkRunV = false;
        if (pointMap.containsKey(stkRun)) {
            stkRunV = Boolean.valueOf(pointMap.get(stkRun).toString());
        }
        if (stkRunV){
            return Result.err().msg("堆垛机正在运行中");
        }

        if(!stkidleV){
            return Result.err().msg("堆垛机繁忙");
        }
        if(!stkGroundV){
            return Result.err().msg("堆垛机地面柜手动状态");
        }

        if(!stkAutoManualV){
            return Result.err().msg("堆垛机手动状态");
        }


        //给堆垛机写命令
        Map<String, Object> allMap = new HashMap<>(1);
        //启动设备
        Map<String, Object> plcStartEqMap = new HashMap<>(1);
        plcStartEqMap.put(plcStartEqValueType, true);
        allMap.put(plcStartEq, plcStartEqMap);

        Map<String, Object> plcTaskIdMap = new HashMap<>(1);
        plcTaskIdMap.put(taskIdvalueType, stkMoveBo.getTaskId());
        allMap.put(plcTaskId, plcTaskIdMap);

        Map<String, Object> plcToRowMap = new HashMap<>(1);
        plcToRowMap.put(toRowValueType, toRow);
        allMap.put(plcToRow, plcToRowMap);

        Map<String, Object> plcToColumnMap = new HashMap<>(1);
        plcToColumnMap.put(toColumnValueType, toColumn);
        allMap.put(plcToColumn, plcToColumnMap);

        Map<String, Object> plcToLayerMap = new HashMap<>(1);
        plcToLayerMap.put(toLayerValueType, toLayer);
        allMap.put(plcToLayer, plcToLayerMap);

        Map<String, Object> plcFromRowMap = new HashMap<>(1);
        plcFromRowMap.put(fromRowValueType, fromRow);
        allMap.put(plcfromRow, plcFromRowMap);

        Map<String, Object> plcFromColumnMap = new HashMap<>(1);
        plcFromColumnMap.put(fromColumnValueType, fromColumn);
        allMap.put(plcfromColumn, plcFromColumnMap);

        Map<String, Object> plcFromLayerMap = new HashMap<>(1);
        plcFromLayerMap.put(fromLayerValueType, fromLayer);
        allMap.put(plcfromLayer, plcFromLayerMap);

        PLCReadAndWrite plcReadAndWrite = new PLCReadAndWrite();

        Boolean boolWrite = plcReadAndWrite.execWrite(stkOperate, JsonUtil.toJSONString(allMap));
         log.info("出库给堆垛机下发命令："+boolWrite+"任务号："+stkMoveBo.getTaskId());
        return boolWrite ? Result.ok() : Result.err();
    }


}
