package com.mushiny.wms.slam;


import com.mushiny.wms.application.business.common.CommonBusiness;
import com.mushiny.wms.application.domain.*;
import com.mushiny.wms.application.domain.enums.TripState;
import com.mushiny.wms.application.domain.enums.TripType;
import com.mushiny.wms.application.repository.*;
import com.mushiny.wms.common.utils.DateTimeUtil;
import com.mushiny.wms.common.utils.EntityManagerUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.Map;

/**
 * Created by Administrator on 2018/10/15.
 */
@Component
@Transactional
public class MideaSlamListener {
    private final static Logger logger = LoggerFactory.getLogger(MideaSlamListener.class);

    public static final String INSTRUCTACK = "InstructAck";
    @Value("${mushiny.midea.slam.url}")
    private String mideaUrl;

    @Value("${mushiny.midea.slam.appSecret}")
    private String appSecret;

    private final RestTemplateBuilder builder;

    private final EntityManagerUtil entityManagerUtil;

    private final MdStationnodepositionRepository mdStationnodepositionRepository;

    private final WmsSlamTripRepository wmsSlamTripRepository;

    private final TripRepository tripRepository;
    private final CommonBusiness commonBusiness;
    private final WCSRobotRepository wcsRobotRepository;
    private final MapNodeRepository mapNodeRepository;

    private final OutboundInstructRepository outboundInstructRepository;

    @Autowired
    public MideaSlamListener(RestTemplateBuilder builder, EntityManagerUtil entityManagerUtil,
                             MdStationnodepositionRepository mdStationnodepositionRepository, WmsSlamTripRepository wmsSlamTripRepository, TripRepository tripRepository, CommonBusiness commonBusiness, WCSRobotRepository wcsRobotRepository, MapNodeRepository mapNodeRepository, OutboundInstructRepository outboundInstructRepository) {
        this.builder = builder;
        this.entityManagerUtil = entityManagerUtil;
        this.mdStationnodepositionRepository = mdStationnodepositionRepository;
        this.wmsSlamTripRepository = wmsSlamTripRepository;
        this.tripRepository = tripRepository;
        this.commonBusiness = commonBusiness;
        this.wcsRobotRepository = wcsRobotRepository;
        this.mapNodeRepository = mapNodeRepository;
        this.outboundInstructRepository = outboundInstructRepository;
    }

    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(value = "", durable = "true"),
            exchange = @Exchange(value = "section1", ignoreDeclarationExceptions = "true"),
            key = INSTRUCTACK))
    public void WCS_SLAM_InstructAck(Message message) {
        byte[] body = message.getBody();
        Map data = (Map) CommonUtils.toObject(body);
        if (data == null || data.isEmpty()) {
            return;
        }
        //处理逻辑
        //RestTemplate restTemplate = builder.build();

        /*{
            "taskId": "任务标识，string (20)，必填 任务更新操作的主键",
            "areaCode": "区域编码，string (50)，选填 ",
            "warehouseCode": "仓库编码，string (50)，选填 例如：南沙空调 4#厂房",
            "taskType": "任务类型，int，必填 0-运送物料 1-空料架回收 2-任务异常处理",
            "startTag": "任务起点，string (50)，选填 ",
            "endTag": "任务终点，string (50) ，必填",
            "storageNo": "料架编码，string (50) ，选填 默认”0” ",
            "priority": "优先级，int，选填，默认 99 0-优先级最高"
            "taskDateTime": "交互当前时间，string（23）， ‘yyyy-MM-DD HH:mm:ss.fff’ "
        }*/

        /* message.put("sectionID",section.getRcs_sectionId());
        message.put(MideaConstants.TRIP_ID,this.getOrderId());
        message.put(MideaConstants.TRIP_TYPE,this.getType());
        message.put(MideaConstants.SOURCE_ADDRESS, this.getWcsPath().getPodUpAddress());
        message.put(MideaConstants.DRIVE_ID, this.getRobot().getRobotId());
        message.put(MideaConstants.POD_INDEX,this.getPod().getPodId());
        message.put(MideaConstants.INSTRUCT_STATUS, MideaConstants.STOCKOUT);*/
        //上个任务终点就是这个任务起点
        //二维码前序任务的目的地是起点
        logger.info("监听RabbitMQ到任务执行完成的消息:" + data);
        String status = CommonUtils.parseString(MideaConstants.INSTRUCT_STATUS,data);
        String targetAddress = CommonUtils.parseString(MideaConstants.TARGET_ADDRESS, data);
        if(!Objects.equals(status, MideaConstants.STOCKOUT)){
            logger.error("不是停止点，任务未完成" + data);
            return;
        }
        String endTag = this.addrCode2Id(CommonUtils.parseString(MideaConstants.TARGET_ADDRESS, data));
        if(CommonUtils.isEmpty(endTag)){
            return;
        }
        logger.debug("二维码AGV目标地址码是:" + CommonUtils.parseString(MideaConstants.TARGET_ADDRESS, data) + " 地址码ID是:" + endTag);

        List<MdStationnodeposition> allSlamInterNodes = this.mdStationnodepositionRepository.getAllSlamInterNodes();
        boolean contains = false;
        for (int i = 0; i < allSlamInterNodes.size(); i++) {
            MdStationnodeposition mdStationnodeposition = allSlamInterNodes.get(i);
            logger.debug(i + ": 接驳点位:" + mdStationnodeposition.getNode().getAddressCodeId());
            if (Objects.equals(mdStationnodeposition.getNode().getId(), endTag)) {
                contains = true;
                break;
            }
        }
        if (!contains) {
            logger.debug("调度单目标点位不是激光AGV出库工作站,无需发送激光AGV指令:"
                    + CommonUtils.parseString(MideaConstants.TARGET_ADDRESS, data));
            return;
        }

        String slamTag = this.node2SlamTag(endTag);

        //Map params = new HashMap();
        String id = CommonUtils.genUUID();
        /*params.put("taskId", id);
        params.put("areaCode","NANSHA");
        params.put("warehouseCode","NANSHA");
        params.put("taskType",0);
        params.put("startTag",slamTag);*/
        String instrutId = CommonUtils.parseString(MideaConstants.INSTRUCT, data);

        /*params.put("endTag", targetTag);
        params.put("storageNo",CommonUtils.parseString(MideaConstants.POD_INDEX,data));
        params.put("priority",99);
        params.put("taskDateTime", DateTimeUtil.getNowFormat("yyyy-MM-DD HH:mm:ss.fff"));*/

        //String instructId = CommonUtils.parseString(MideaConstants.INSTRUCT,data);
        String tripId = CommonUtils.parseString(MideaConstants.TRIP_ID, data);

        OutboundInstruct outboundInstruct = this.outboundInstructRepository.getInstruByTripId(tripId);

        String targetTag = this.getEndTag(outboundInstruct);
        if(CommonUtils.isEmpty(targetTag)){
            logger.error("执行到SLAM出库位的货架，在出库指令里未定义SLAM站点:"+outboundInstruct);
            return;
        }
        WmsSlamTrip wmsSlamTrip = new WmsSlamTrip();
        wmsSlamTrip.setId(id);
        wmsSlamTrip.setAreaCode("NANSHA");
        wmsSlamTrip.setWarehouseCode("NANSHA");
        wmsSlamTrip.setTaskType(WmsSlamTrip.TASKTYPE_OUT);
        wmsSlamTrip.setStartTag(slamTag);
        wmsSlamTrip.setEndTag(targetTag);
        wmsSlamTrip.setPriority(99);
        wmsSlamTrip.setStorageNo(CommonUtils.parseString(MideaConstants.POD_INDEX, data));
        wmsSlamTrip.setTaskDateTime(DateTimeUtil.getNowFormat("yyyy-MM-DD HH:mm:ss"));//todo
        wmsSlamTrip.setTripState(WmsSlamTrip.AVAILABLE);
        //增加billType inv_org_id
        wmsSlamTrip.setBillType(outboundInstruct.getBILL_TYPE());
        wmsSlamTrip.setInvOrgId(outboundInstruct.getINV_ORG_ID());
        wmsSlamTrip.setInstructId(outboundInstruct.getId());//TODO
        //this.wmsSlamTripRepository.save(wmsSlamTrip);
        this.wmsSlamTripRepository.saveAndFlush(wmsSlamTrip);
        logger.info("生成SLAM的调度任务，WMS_SLAM_TRIP:" + id);
        //查找目标工位
        /*String sign = this.exportSign(params);

        HttpHeaders headers = new HttpHeaders();
        MediaType type = MediaType.parseMediaType("application/json; charset=UTF-8");
        headers.setContentType(type);
        headers.add("Accept", MediaType.APPLICATION_JSON.toString());
        HttpEntity<String> httpEntity = new HttpEntity<String>(sign, headers);
        ResponseEntity<String> responseEntity = restTemplate.postForEntity(this.mideaUrl, httpEntity, String.class);
        logger.info("Slam服务器返回数据是:"+responseEntity.getBody());*/
        //TODO
        checkIfEmptyRun(CommonUtils.parseString(MideaConstants.DRIVE_ID, data)
                , CommonUtils.parseString(MideaConstants.TRIP_ID, data));
        logger.info("结束监听RabbitMQ到任务执行完成的消息:" + data);
    }

    private void checkIfEmptyRun(String robotId, String tripId) {
        List params = new ArrayList();
        params.add("Available");
        params.add("Process");
        List<Trip> trips = this.tripRepository.getAllByRobotId(robotId, params);
        boolean needEmptyRun = true;
        for (int i = 0; i < trips.size(); i++) {
            Trip trip = trips.get(i);
            if (Objects.equals(trip.getId(), trip)) {
                continue;
            } else {
                needEmptyRun = false;
                break;
            }
        }

        if (!needEmptyRun) {
            logger.error("小车" + robotId + "已有其他任务 无需创建EmptyRun!");
            return;
        }

        String sectionId = "ec229eb7-7e2b-43a8-b1c7-91bd807e91cf";
        WCSRobot robot = this.wcsRobotRepository.getWCSRobotByRobotId(robotId,sectionId);
        try {
            Integer moveTargetAddress = commonBusiness.getTargetAddress(sectionId, robot.getAddressCodeId());

            Trip moveTrip = new Trip();
            moveTrip.setTripType(TripType.MOVE_DRIVE.getName());
            moveTrip.setTripState(TripState.AVAILABLE.getName());
            moveTrip.setDriveId(robotId);
            moveTrip.setEndAddress(moveTargetAddress);
            moveTrip.setSectionId(sectionId);
            moveTrip.setWarehouseId("DEFAULT");
            moveTrip = tripRepository.saveAndFlush(moveTrip);
            if (logger.isDebugEnabled()) {
                logger.debug("生成出库小车 {} 调走的调度单{}成功 目标{}", robotId, moveTrip.getId(),moveTargetAddress);
            }
        } catch (Exception e) {
            logger.error("生成出库小车调走任务EmptyRun失败" + e.getMessage(), e);
        }

    }

    private static final String sql3 = "SELECT SLAM_NODE FROM WMS_SLAM_NODE " +
            "WHERE SLAM_NODENAME=:workcenterCode OR SLAM_NODENAME=:lineCode";

    private String getEndTag(OutboundInstruct instrutId) {
        String workcenterCode = instrutId.getWORKCENTER_CODE();
        String lineCode = instrutId.getLINE_CODE();
        Map param = new HashMap();
        param.put("workcenterCode", workcenterCode);
        param.put("lineCode", lineCode);
        logger.error(sql3+"\n params:"+param);
        List<Map> nodes = this.entityManagerUtil.executeNativeQuery2(sql3, param);
        if (nodes != null && !nodes.isEmpty()) {
            Map data = nodes.get(0);
            return (String) data.get("SLAM_NODE");
        }
        return null;
    }

    private static final String sql2 = "SELECT * FROM WMS_SLAM_NODE WHERE NODEID=:nodeId";

    private String node2SlamTag(String endTag) {
        if(CommonUtils.isEmpty(endTag)){
            logger.error("地址码是空" + endTag);
            return null;
        }
        Map param = new HashMap();
        param.put("nodeId", endTag);

        List<Map> nodes = this.entityManagerUtil.executeNativeQuery2(sql2, param);
        if (nodes != null && !nodes.isEmpty()) {
            Map data = nodes.get(0);
            return (String) data.get("SLAM_NODE");
        }
        return null;
    }

    private static final String sql = "SELECT * FROM WD_NODE WHERE ADDRESSCODEID=:addrCode AND MAP_ID = '8a55cdc8-dd5c-4a07-87e7-3979511949de'";

    //地址码转ID

    private String addrCode2Id(String source) {
        Map param = new HashMap();
        param.put("addrCode", source);
        MapNode node = this.mapNodeRepository.getByAddressCodeId("8a55cdc8-dd5c-4a07-87e7-3979511949de", Integer.parseInt(source));
        return node == null ? null : node.getId();
    }

    private String exportSign(Map params) {
        List keys = new ArrayList();
        keys.addAll(params.keySet());
        Collections.sort(keys);
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append(this.appSecret);
        for (int i = 0; i < keys.size(); i++) {
            String key = (String) keys.get(i);
            stringBuilder.append(key).append(CommonUtils.parseString(key, params));
        }
        stringBuilder.append(this.appSecret);

        logger.debug("拼接后的字符串是:" + stringBuilder);
        String md5Str = CommonUtils.md5(stringBuilder.toString());
        logger.debug("MD5的字符串是:" + stringBuilder);
        return md5Str;
    }
}
