package com.shkj.wcs.third.rcs;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.http.HttpRequest;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
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.system.service.ISysParameterService;
import com.shkj.wcs.bo.AGVStatesBo;
import com.shkj.wcs.bo.AGVUploadStatusBo;
import com.shkj.wcs.domain.WcsPlcConnect;
import com.shkj.wcs.domain.WcsPlcProperty;
import com.shkj.wcs.plc.PlcInit;
import com.shkj.wcs.service.IWcsPlcConnectService;
import com.shkj.wcs.service.IWcsPlcPropertyService;
import com.shkj.wcs.third.rcs.dto.RcsCancelTaskDto;
import com.shkj.wcs.third.rcs.dto.RcsCreateTaskDto;
import com.shkj.wcs.third.rcs.dto.RcsIdList;
import com.shkj.wcs.third.rcs.dto.RcsThirdResult;
import com.shkj.wms.bo.AGVMoveBo;
import com.shkj.wms.bo.BusinDataTaskDatailAddBo;
import com.shkj.wms.bo.BusinTaskAddBo;
import com.shkj.wms.bo.BusinTaskQueryBo;
import com.shkj.wms.constants.ParameterConstants;
import com.shkj.wms.domain.BusinDataTask;
import com.shkj.wms.domain.BusinDataTaskDetail;
import com.shkj.wms.mapper.BusinDataTaskMapper;
import com.shkj.wms.service.IBusinDataTaskDetailService;
import com.shkj.wms.service.IBusinDataTaskService;
import com.shkj.wms.utils.JsonUtil;
import com.shkj.wms.vo.BusinDataTaskVo;
import lombok.extern.slf4j.Slf4j;
import org.checkerframework.checker.units.qual.A;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * AGV 接口文档
 *
 * @author zjx
 * @date 2023/04/08
 */
@Slf4j
@Component
public class RCSUtil {

    @Value("${third.agvCreateTaskUrl:}")
    private String agvCreateTaskUrl;

    @Value("${third.agvCancelTaskUrl:}")
    private String agvCancelTaskUrl;

    @Value("${third.agvStatesUrl:}")
    private String agvStatesUrl;

    @Value("${third.queryAckByTaskUrl:}")
    private String queryAckByTaskUrl;

    @Autowired
    IBusinDataTaskDetailService iBusinDataTaskDetailService;


    @Autowired
    BusinDataTaskMapper businDataTaskMapper;

    @Resource
    RedisTemplate redisTemplate;

    @Autowired
    IWcsPlcPropertyService iWcsPlcPropertyService;

    @Autowired
    PLCReadAndWrite plcReadAndWrite;

    @Autowired
    ISysParameterService isysParameterService;

    @Autowired
    IWcsPlcConnectService iWcsPlcConnectService;

    @Autowired
    IBusinDataTaskService iBusinDataTaskService;

    @Autowired
    PlcInit plcInit;


    /**
     * 设置头部信息
     *
     * @return {@code Map<String, String>}
     */
    public Map<String, String> getHeaderMap() {
        Map<String, String> headerMap = new HashMap<>(1);
        headerMap.put("authorization", "mrbase64 mrrest:YWRtaW4mYWRtaW4=");
        return headerMap;
    }


    /**
     * 创建任务
     * wcs系统通过此接口向rcs系统下发创建任务指令
     *
     * @param dto dto
     * @return {@code Result}
     */
    public Result rcsCreateTask(RcsCreateTaskDto dto) {
        String json = JSONObject.toJSONString(dto);
        try {
            Map<String, String> headerMap = getHeaderMap();
            String res = HttpRequest.post(agvCreateTaskUrl)
                    .addHeaders(headerMap)
                    .body(json)
                    .execute().body();
            Result result = parseThirdRcsResult(res);
            return result;
        } catch (Exception e) {
            e.printStackTrace();
            log.error("createTask 方法出错了 = {}", e.getMessage());
            return Result.err().msg(e.getMessage());
        }
    }


    /**
     * 放行任务
     * wcs系统通过此接口向rcs系统下发放行任务指令
     *
     * @param dto dto
     * @return {@code Result}
     */
    public Result queryAck(RcsCreateTaskDto dto) {
        String json = JSONObject.toJSONString(dto);
        try {
            Map<String, String> headerMap = getHeaderMap();
            String res = HttpRequest.post(queryAckByTaskUrl)
                    .addHeaders(headerMap)
                    .body(json)
                    .execute().body();
            return parseThirdRcsResult(res);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("放行 方法出错了 = {}", e.getMessage());
            return Result.err().msg(e.getMessage());
        }
    }

    public Result parseThirdRcsResult(String res) {
        try {
            res = res.trim();
            RcsThirdResult thirdResult = JSONObject.parseObject(res, RcsThirdResult.class);
            if (thirdResult == null) {
                // 添加到异常中去
                return Result.err().msg(res);
            }
            if (!RcsThirdResult.isOk(thirdResult)) {
                return Result.err().msg(res);
            }
            return Result.ok();
        } catch (Exception e) {
            log.error("parseThirdRcsResult res = {} e = {}", res, e);
            return Result.err().msg(res);
        }
    }

    /**
     * 任务取消
     * 上游系统调⽤此接⼝，将已下发待处理的任务取消
     *
     * @param /rest/tasks/del
     * @return {@code Result}
     */
    public Result rcsTaskCancel(RcsCancelTaskDto dto) {
        String json = JSONObject.toJSONString(dto);

        try {
            Map<String, String> headerMap = getHeaderMap();
            String res = HttpRequest.post(agvCancelTaskUrl)
                    .addHeaders(headerMap)
                    .body(json)
                    .execute().body();

            return parseThirdRcsResult(res);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("rcs taskCancel 方法出错了 = {}", e.getMessage());
            return Result.err().msg(e.getMessage());
        }
    }


    /**
     * AGV搬运
     *
     * @param bo
     * @return {@link Result}<{@link Boolean}>
     */
    public Result<Boolean> moveByAGV(AGVMoveBo bo) {
        RcsCreateTaskDto dto = new RcsCreateTaskDto();
        dto.setMapId(1);
        dto.setTaskType(bo.getTaskType());
        dto.setTaskId(bo.getTaskId().toString());
        //库位编号
        List<RcsIdList> idList = new ArrayList<>();
        List<String> points = bo.getPoints();
        for (String point : points) {
            RcsIdList rcsIdList = new RcsIdList();
            rcsIdList.setId(point);
            log.error(point);
            idList.add(rcsIdList);
        }
        dto.setTargets(idList);
         return rcsCreateTask(dto);
//           return Result.ok();
    }



    public Result<Boolean> moveByAGVTmp(BusinTaskQueryBo bo) {
        //呼叫AGV
        String targetPoint  = isysParameterService.selectConfigByKey(ParameterConstants.ParameterSystem.putin_point);
        String tmpPoint = isysParameterService.selectConfigByKey(ParameterConstants.ParameterSystem.putout_point_tmp);
        String startPoint = isysParameterService.selectConfigByKey(ParameterConstants.ParameterSystem.target_point);

        //根据关键字查询任务号及AGV编号
        BusinDataTaskVo vo = businDataTaskMapper.selectBusinDataTaskByKeys(bo);
        String agvNo = "";//vo.getAgvNo();

        Long plcId = 0L;//vo.getPlcId();
        String taskCode = "T_" + DateUtils.dateTimeNow();
        //创建任务
        BusinTaskAddBo businTaskAddBo = new BusinTaskAddBo();
        //ZJ100001
        businTaskAddBo.setContainerId(1L);
        businTaskAddBo.setPlcId(plcId);
        businTaskAddBo.setBatch(DateUtils.getDate());
        businTaskAddBo.setTaskType("0");
        businTaskAddBo.setTaskCode(taskCode);

        Map<String,String> snPointMap = new HashMap<>(3);
        snPointMap.put("1",startPoint);
        snPointMap.put("2",tmpPoint);
        snPointMap.put("3",tmpPoint);
        snPointMap.put("4",targetPoint);

        //新增任务单据
        businTaskAddBo.setTaskStatus("1");
        businTaskAddBo.setPoints(JsonUtil.toJSONString(snPointMap));
        BusinDataTask businDataTask = BeanUtil.toBean(businTaskAddBo, BusinDataTask.class);
        iBusinDataTaskService.insertBusinDataTask(businDataTask);
        Long taskId =businDataTask.getId();
        RcsCreateTaskDto dto = new RcsCreateTaskDto();
        dto.setMapId(1);
        dto.setTaskType(25);
        dto.setTaskId(taskId.toString());
        dto.setRobotId(agvNo);
        //点位编号
        List<RcsIdList> idList = new ArrayList<>();
        RcsIdList startId = new RcsIdList();
        RcsIdList midId = new RcsIdList();
        RcsIdList midIdTwo = new RcsIdList();
        RcsIdList endId = new RcsIdList();

        startId.setId(startPoint);
        midId.setId(tmpPoint);
        midIdTwo.setId(tmpPoint);
        endId.setId(targetPoint);
        idList.add(startId);
        idList.add(midId);
        idList.add(midIdTwo);
        idList.add(endId);
        dto.setTargets(idList);
         return rcsCreateTask(dto);
    }

    /**
     * 获取AGV实时状态信息
     *
     * @param mapId bo
     * @return {@code Result}
     */
    public Result rcsRobotsStates(String mapId) {
        String json = JSONObject.toJSONString(mapId);
        try {
            Map<String, String> headerMap = getHeaderMap();
            String res = HttpRequest.post(agvStatesUrl)
                    .addHeaders(headerMap)
                    .body(json)
                    .execute().body();
            //获取AGV状态信息 推送前端及存储数据库及存储redis TODO
            return parseThirdRcsResult(res);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("createTask 方法出错了 = {}", e.getMessage());
            return Result.err().msg(e.getMessage());
        }
    }


    /**
     * AGV上报任务每一步状态
     *
     * @param bo bo
     * @return {@code Result}
     */
    public Result<AGVStatesBo> uploadAgvTaskStatus(AGVUploadStatusBo bo) {



        Long plcId = (Long) redisTemplate.opsForValue().get(RedisConstant.redistaskPlc + bo.getTaskId().toString());

        //根据plcId获取plc信息
        WcsPlcConnect wcsplc = (WcsPlcConnect) redisTemplate.opsForValue().get(RedisConstant.redisPlcConnect + plcId);

        List<WcsPlcProperty> propertyList = iWcsPlcPropertyService.getWcsPlcPropertyByPlcId(plcId);
        String writeTaskId = "";
        String valueType = "";
        for (WcsPlcProperty wcsPlcProperty : propertyList) {
            //AGV取走完成
            if (wcsPlcProperty.getPointType().equals("7")) {
                writeTaskId = wcsPlcProperty.getAddress();
                valueType = wcsPlcProperty.getValueType();
            }
        }

        Map<String, String> writeMap = new HashMap<>(1);
        writeMap.put(valueType, "true");
        Map<String, Object> allMap = new HashMap<>(1);
        allMap.put(writeTaskId, writeMap);

        Map<String, String> readMap = new HashMap<>(1);
        readMap.put(writeTaskId, valueType);

        PlcOperate plcOperate = plcInit.getPlcOperateByIp(wcsplc.getPlcIp());
        //回填plc状态
        PLCReadAndWrite plcReadAndWrite = new PLCReadAndWrite();
        //首先读取任务编号，同目前返回的任务编号是否一致，如果一致则回填状态；
        Map<String, Object> stringObjectMap = plcReadAndWrite.readPlcData(plcOperate, JSONObject.toJSONString(readMap));
        //if(stringObjectMap.get(writeTaskId).equals(bo.getTaskId())){
        plcReadAndWrite.execWrite(plcOperate, JSONObject.toJSONString(allMap));
        //}
        return Result.ok();
    }


    /**
     * AGV上报任务每一步状态
     *
     * @param
     * @return {@code Result}
     */
    public Result uploadAgvTaskStatusTmp(AGVUploadStatusBo bo) {
        log.error("taskid:" + String.valueOf(bo.getTaskId()));
        log.error("status:" + String.valueOf(bo.getStatus()));
        log.error("sn:" + String.valueOf(bo.getSn()));
        log.error("robotid:" + String.valueOf(bo.getRobotId()));
        BusinDataTask businDataTask = businDataTaskMapper.selectById(bo.getTaskId());
        log.error("任务:" + businDataTask.toString());
        Long plcId = businDataTask.getPlcId();
        String points = businDataTask.getPoints();
        Map<String, String> agvMap = JsonUtil.JsonStrToMap(points);
        log.error(agvMap.toString());


        WcsPlcConnect conn = iWcsPlcConnectService.selectWcsPlcConnectById(plcId);
        String readAddress = "";
        String readValueType = "";
        String agvPoint="";

        String putAddress = "";
        String putAddressVtype = "";
        String putAgvPoint ="";
        Result result = new Result();
        result.setCode(200);
        result.setResult(true);

        List<WcsPlcProperty> propertyList = iWcsPlcPropertyService.getWcsPlcPropertyByPlcId(plcId);
        for (WcsPlcProperty wcsPlcProperty : propertyList) {
            if (wcsPlcProperty.getPointType().equals("8")) {
                //放料完成点位
                putAddress = wcsPlcProperty.getAddress();
                putAddressVtype = wcsPlcProperty.getValueType();
                agvPoint =wcsPlcProperty.getRelPoint();

            } else if (wcsPlcProperty.getPointType().equals("1")) {
                //点位类型=1，是否允许放料
                readAddress = wcsPlcProperty.getAddress();
                readValueType = wcsPlcProperty.getValueType();
                putAgvPoint=wcsPlcProperty.getRelPoint();
            }
        }

        //更新任务数据
        List<String> collect = agvMap.entrySet().stream().sorted(Map.Entry.comparingByKey()).map(e -> e.getKey()).collect(Collectors.toList());
        log.error(collect.get(collect.size() - 1));
        log.error(bo.getSn());
        if ((collect.get(collect.size() - 1).equals(bo.getSn())) && (Integer.valueOf(collect.size()) <= 2)) {
            businDataTask.setTaskStatus("4");
            log.error("更新小任务状态位2-----完成");
        }
        businDataTask.setAgvNo(bo.getRobotId());
        businDataTask.setUpdateTime(DateUtils.getNowDate());
        businDataTaskMapper.updateById(businDataTask);

        //新增AGV明细数据
        BusinDataTaskDatailAddBo bdtdBo = new BusinDataTaskDatailAddBo();
        bdtdBo.setTaskCode(bo.getTaskId());
        bdtdBo.setRobotId(bo.getRobotId());
        bdtdBo.setIsState(bo.getStatus());
        bdtdBo.setExecDev("AGV");
        bdtdBo.setSn(bo.getSn());
        iBusinDataTaskDetailService.insertBusinTaskDetail(BeanUtil.toBean(bdtdBo, BusinDataTaskDetail.class));

        PlcOperate plcOperate = plcInit.getPlcOperateByIp(conn.getPlcIp());

        Map allWriteMap = new HashMap(2);
        String taskAgvpoint = agvMap.get(bo.getSn());

        //放置治具完成状态，回填AGV放置治具完成状态
        if (bo.getStatus().equals("completed") && agvPoint.equals(taskAgvpoint)) {
            Map writeMap = new HashMap(1);
            writeMap.put(putAddressVtype, "true");
            allWriteMap.put(putAddress, writeMap);
            plcReadAndWrite.execWrite(plcOperate, JSON.toJSONString(allWriteMap));
            return Result.ok();
        }

        //是否允许放料
        if (bo.getStatus().equals("started") && putAgvPoint.equals(taskAgvpoint)) {
            Map<String, String>  readMap = new HashMap<>(1);
            readMap.put(readAddress, readValueType);
            Map<String, Object> pointMap = plcReadAndWrite.readPlcData(plcOperate, JSON.toJSONString(readMap));
            log.error(readAddress);
//            log.error(pointMap.get(readAddress).toString());
            Boolean next=!Boolean.valueOf(pointMap.get(readAddress).toString());
            if(pointMap.isEmpty()){
                next=true;
            }
            if (pointMap.containsKey(readAddress) && next) {

                result.setCode(503);
                result.setResult(false);
                log.error("放行失败");
                log.error("code:" + result.getCode() + "    result:" + result.getResult());
                return result;
            }else {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                new Thread(() -> {
                    try {
                        Thread.sleep(1500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    RcsCreateTaskDto taskDto = new RcsCreateTaskDto();
                    taskDto.setTaskId(bo.getTaskId().toString());
                    queryAck(taskDto);
                    log.error("放行成功");
                }).start();
            }
        }
        return Result.ok();
    }
}
