package com.shkj.wms.plc;

import cn.hutool.core.bean.BeanUtil;
import com.shkj.common.core.domain.Result;
import com.shkj.common.core.domain.entity.BaseConsignor;
import com.shkj.common.enums.HttpStatus;
import com.shkj.common.utils.DateUtils;
import com.shkj.plc.sdk.device.PLCReadAndWrite;
import com.shkj.plc.sdk.device.PlcOperate;
import com.shkj.system.service.ISysParameterService;
import com.shkj.wms.domain.WcsPlcConnect;
import com.shkj.wms.domain.WcsPlcProperty;
import com.shkj.wms.service.IWcsPlcConnectService;
import com.shkj.wms.service.IWcsPlcPropertyService;
import com.shkj.wms.third.rcs.RCSUtil;
import com.shkj.wms.vo.WcsPlcConnectVo;
import com.shkj.wms.bo.*;
import com.shkj.wms.constants.ParameterConstants;
import com.shkj.wms.domain.BusinDataTask;
import com.shkj.wms.mapper.BusinDataTaskMapper;
import com.shkj.wms.service.IBaseGoodsDataService;
import com.shkj.wms.service.IBusinDataTaskDetailService;
import com.shkj.wms.service.IBusinDataTaskService;
import com.shkj.wms.service.IPutInOutStorageService;
import com.shkj.wms.utils.JsonUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
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;

@Component("PlcEventTmpTask")
@Slf4j
public class PlcEventTmpTask {

    @Autowired
    IWcsPlcConnectService iWcsPlcConnectService;

    @Autowired
    RCSUtil rcsUtil;

    @Autowired
    IWcsPlcPropertyService iWcsPlcPropertyService;

    @Autowired
    IBusinDataTaskService iBusinDataTaskService;

    @Autowired
    IPutInOutStorageService iPutInOutStorageService;

    @Autowired
    ISysParameterService isysParameterService;

    @Resource
    IBaseGoodsDataService iBaseGoodsDataService;


    @Autowired
    IBusinDataTaskDetailService iBusinDataTaskDetailService;


    private int number = 1;

    @Resource
    PlcInit plcInit;

//    @PostConstruct
    public void init() {

        //查询需要连接的PLC,初始化连接对象
        List<WcsPlcConnectVo> plcList = iWcsPlcConnectService.selectWcsPlcConnectList(new WcsPlcConnect().setIsActive("1"));
        if (plcList.size() == 0) {
            return;
        }


        for (WcsPlcConnectVo conn : plcList) {

            if(conn.getPlcIp().contains(".41")){
                plcTask(plcInit.getPlcOperate_41(), conn, conn.getPointTables());
            }

            if(conn.getPlcIp().contains(".50")){
                plcTask(plcInit.getPlcOperate_50(), conn, conn.getPointTables());
            }

            if(conn.getPlcIp().contains(".60")){
                plcTask(plcInit.getPlcOperate_60(), conn, conn.getPointTables());
            }

            if(conn.getPlcIp().contains(".70")){
                plcTask(plcInit.getPlcOperate_70(), conn, conn.getPointTables());
            }

            if(conn.getPlcIp().contains(".80")){
                plcTask(plcInit.getPlcOperate_80(), conn, conn.getPointTables());
            }

            if(conn.getPlcIp().contains(".90")){
                plcTask(plcInit.getPlcOperate_90(), conn, conn.getPointTables());
            }

            if(conn.getPlcIp().contains(".100")){
                plcTask(plcInit.getPlcOperate_100(), conn, conn.getPointTables());
            }

            if(conn.getPlcIp().contains(".110")){
                plcTask(plcInit.getPlcOperate_110(), conn, conn.getPointTables());
            }
        }
    }


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

        try {
            Result<BaseConsignor> result = iBaseGoodsDataService.getErpConsignorId();
            if (!Result.isOk(result)) {
                log.error(result.getMsg());
            }
            //获取仓库ID
            BaseConsignor baseConsignor = result.getData();
            Long branchId  =baseConsignor.getBranchId();

            Long plcId = conn.getId();
            //根据连接的plcId获取属性
            PLCReadAndWrite plcReadAndWrite = new PLCReadAndWrite();
            Map<String, Object> pointMap = plcReadAndWrite.readPlcData(plcOperate, pointTables);

            List<WcsPlcProperty> propertyList = iWcsPlcPropertyService.getWcsPlcPropertyByPlcId(plcId);
            Long taskId = 0L;
            //生产环境依据设备类型来判断
            switch (conn.getDevType()) {
                //机械手区域输送线保险杠到达请求，处理业务逻辑入库及呼叫AGV
                case "2":
                    String readAddress = "";
                    String writeTaskId = "";
                    String valueType = "";

                    String heartbeat = "";
                    String hbValueType = "";

                    String writeopen="";
                    String writeopenType="";
                    for (WcsPlcProperty wcsPlcProperty : propertyList) {
                        //产品到达出入口请求AGV
                        if (wcsPlcProperty.getPointType().equals("5")) {
                            readAddress = wcsPlcProperty.getAddress();
                            //任务ID
                        } else if (wcsPlcProperty.getPointType().equals("6")) {
                            writeTaskId = wcsPlcProperty.getAddress();
                            valueType = wcsPlcProperty.getValueType();
                        } else if (wcsPlcProperty.getPointType().equals("9")) {
                            //心跳
                            heartbeat = wcsPlcProperty.getAddress();
                            hbValueType = wcsPlcProperty.getValueType();
                        }else if (wcsPlcProperty.getPointType().equals("1")){
                            //是否放行
                            writeopen= wcsPlcProperty.getAddress();
                            writeopenType= wcsPlcProperty.getValueType();
                        }
                    }

                    log.error("是否放行点位为:"+writeopen);
                    log.error("是否放行类型为:"+writeopenType);

                    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(hbValueType, heartbeatV);
                    Map<String, Object> allHbMap = new HashMap<>(1);
                    allHbMap.put(heartbeat, writeHbMap);
                    plcReadAndWrite.execWrite(plcOperate, JsonUtil.toJSONString(allHbMap));
                    log.error("是否有点位信息"+pointMap.containsKey(writeopen));
                    log.error("点位信息为是否可以放行"+Boolean.valueOf(pointMap.get(writeopen).toString()));
                    if (pointMap.containsKey(writeopen) && Boolean.valueOf(pointMap.get(writeopen).toString())){
                        Map map = new HashMap();
                        map.put("mapId",1);
                        map.put("posId","KW16");
                        //rcsUtil.openRun(map);
                    }

                    log.error("是否自动"+Boolean.valueOf(pointMap.get(readAddress).toString()));
                    log.error("任务号是否为0:"+Integer.valueOf(pointMap.get(writeTaskId).toString()));
                    if (pointMap.containsKey(readAddress) && Boolean.valueOf(pointMap.get(readAddress).toString())) {
                        log.error("机械手输送线为自动且开始创建任务=============================================================================");

                        int plcTaskIdValue = Integer.valueOf(pointMap.get(writeTaskId).toString());

                        //PLC读取的任务ID等于0时，呼叫agv后，创建任务后，回填系统生成的任务ID

                        /**
                         * 模拟治具号
                         */
                        if (plcTaskIdValue ==0) {
                            Long a=0L;
                            if (number%4==1){
                                a=3069L;
                            }
                            if (number%4==2){
                                a=3070L;
                            }
                            if (number%4==3){
                                a=3071L;
                            }
                            if (number%4==0){
                                a=3072L;
                            }
                            number++;

                            String taskCode = "T_" + DateUtils.dateTimeNow();

                            BusinTaskAddBo businTaskAddBo = new BusinTaskAddBo();
                            //ZJ100001 治具的ID
                            businTaskAddBo.setContainerId(a);
                            businTaskAddBo.setPlcId(plcId);
                            businTaskAddBo.setBatch(DateUtils.getDate());
                            businTaskAddBo.setTaskType("0");
                            businTaskAddBo.setTaskCode(taskCode);
                            //呼叫AGV
                            String startPoint = isysParameterService.selectConfigByKey(branchId, ParameterConstants.ParameterSystem.putout_point);
                            String targetPoint = isysParameterService.selectConfigByKey(branchId, ParameterConstants.ParameterSystem.target_point);
                            /*startPoint="A";
                            targetPoint="B";*/
                            List<String> agvPoints = new ArrayList<>();
                            agvPoints.add("KW17");
                            agvPoints.add("LY106");
//                            agvPoints.add("rk02-1");
//                            agvPoints.add("rk02-1");
                            agvPoints.add("KW16");
                            agvPoints.add("KW17");


                            Map<String,String> snPointMap = new HashMap<>(3);
                            snPointMap.put("1","KW17");
                            snPointMap.put("2","LY106");
//                            snPointMap.put("3","rk02-1");
//                            snPointMap.put("4","rk02-1");
                            snPointMap.put("3","KW16");
                            snPointMap.put("4", "KW17");


                            //新增任务单据
                            businTaskAddBo.setPoints(JsonUtil.toJSONString(snPointMap));
                            businTaskAddBo.setTaskStatus("1");
                            BusinDataTask businDataTask = BeanUtil.toBean(businTaskAddBo, BusinDataTask.class);
                            iBusinDataTaskService.insertBusinDataTask(businDataTask);
                            taskId=businDataTask.getId();

                            if (taskId != 0){
                                //呼叫AGV
                                AGVMoveBo bo = new AGVMoveBo();
                                //起始点位
                                bo.setFromLocation(startPoint);
                                //任务编号
                                bo.setTaskId(Long.valueOf(taskId));
                                //任务类型
                                bo.setTaskType(127);
                                //目的点位
                                bo.setToLocation(targetPoint);
                                bo.setPoints(agvPoints);
                                Result<Boolean> agvResult = rcsUtil.moveByAGV(bo);
                                log.error("下发任务完成===============================================================================================");
                            }

                            //回填任务号
                            Map<String, Long> writeMap = new HashMap<>(1);
                            writeMap.put(valueType, taskId);
                            Map<String, Object> allMap = new HashMap<>(1);
                            allMap.put(writeTaskId, writeMap);
                            log.error("回填任务号");
                            plcReadAndWrite.execWrite(plcOperate, JsonUtil.toJSONString(allMap));
                        }

                        log.error("创建任务线程结束================================================================================================");

                    }
                    break;

                default:
                    break;
            }

        } catch (Exception e) {
            log.error("plc======================" + e.getMessage());
        }
    }
//    @PostConstruct
    public void testinit(){
        this.testRCS();
    }
    public void testRCS(){
        List<Pair<String, Integer>> list = new ArrayList<>();
        list.add(new ImmutablePair<>("RKu1", 2));
        list.add(new ImmutablePair<>("RKu2", 2));
        list.add(new ImmutablePair<>("RKu3", 2));
        list.add(new ImmutablePair<>("RKu4", 2));
        list.add(new ImmutablePair<>("Cku", 2));
        list.add(new ImmutablePair<>("Cku1", 2));
        list.add(new ImmutablePair<>("Cku2", 2));
        list.add(new ImmutablePair<>("Cku3", 2));
        list.add(new ImmutablePair<>("Cku4", 2));
        list.add(new ImmutablePair<>("CKong", 1));
        list.add(new ImmutablePair<>("YChang", 1));
        list.add(new ImmutablePair<>("HLiu1", 1));
        list.add(new ImmutablePair<>("HLiu2", 1));
        list.add(new ImmutablePair<>("HLiu3", 1));
        list.add(new ImmutablePair<>("HLiu4", 1));
        WeightRandomStrategy<String, Integer> strategy = new WeightRandomStrategy<>(list);
        String fromPoint="";
        String toPoint="";
        for (int i=1;i<=1000;i++){
            String randome = strategy.randome();
            switch (randome){
                case "RKu1":
                    fromPoint="KW17";
                    toPoint="KW5";
                    break;
                case "RKu2":
                    fromPoint="KW17";
                    toPoint="KW7";
                    break;
                case "RKu3":
                    fromPoint="KW17";
                    toPoint="KW9";
                    break;
                case "RKu4":
                    fromPoint="KW17";
                    toPoint="KW18";
                    break;
                case "Cku1":
                    fromPoint="KW6";
                    toPoint="assemble_point";
                    break;
                case "Cku2":
                    fromPoint="KW8";
                    toPoint="assemble_point";
                    break;
                case "Cku3":
                    fromPoint="KW10";
                    toPoint="assemble_point";
                    break;
                case "Cku4":
                    fromPoint="P_out01";
                    toPoint="assemble_point";
                    break;
                case "CKong":
                    fromPoint="KW17";
                    toPoint="E_machine02";
                    break;
                case "YChang":
                    fromPoint="KW17";
                    toPoint="P_Lane01";
                break;
                case "HLiu1":
                    fromPoint="assemble_point";
                    toPoint="KW16";
                    break;
                case "HLiu2":
                    fromPoint="P_Lane01";
                    toPoint="KW16";
                    break;
                case "HLiu3":
                    fromPoint="E_machine02";
                    toPoint="KW16";
                    break;
                case "HLiu4":
                    fromPoint="P_Lane01";
                    toPoint="KW6";
                    break;
            }
            List<String> agvPoints = new ArrayList<>();
            agvPoints.add(fromPoint);
            agvPoints.add(toPoint);
            //呼叫AGV
            AGVMoveBo bo = new AGVMoveBo();
            //起始点位
            bo.setFromLocation(fromPoint);
            //任务编号
            bo.setTaskId(Long.valueOf("10000"+String.valueOf(i)));
            //任务类型
            bo.setTaskType(29);
            //目的点位
            bo.setToLocation(toPoint);
            bo.setPoints(agvPoints);
            Result<Boolean> agvResult = rcsUtil.moveByAGV(bo);
            log.error("开始呼叫agv");
            if(agvResult.getCode()== HttpStatus.SUCCESS.getCode()){
                log.error("呼叫agv成功:任务号"+i+";起点:"+fromPoint+";终点:"+toPoint);
                try {
                    if (i<12){
                        Thread.sleep(1000);
                    }else {
                        Thread.sleep(36000);
                    }
                }catch (Exception e){
                    log.error(e.toString());
                }

            }
        }
    }
}

class WeightRandomStrategy<k, V extends Number> {
    private TreeMap<Double, k> weightMap = new TreeMap<>();
    private Map<String, Integer> map =new HashMap();
    private Map nmap =new HashMap();
    private TreeMap<Double,k> Map = new TreeMap<>();

    public WeightRandomStrategy(List<Pair<k, V>> list) {
        for (Pair<k, V> pair : list) {
            nmap.put(pair.getKey(),pair.getValue());
            map.put(String.valueOf(pair.getKey()),0);
            double lastWeight = this.weightMap.size() == 0 ? 0 : this.weightMap.lastKey();
            this.weightMap.put(pair.getValue().doubleValue() + lastWeight, pair.getKey());
        }
    }

    public java.lang.String randome(){
        Map.putAll(weightMap);
        String k = random();
        return k;
    }

    public String random() {

        Double aDouble = this.Map.lastKey();
        double random = Math.random();
        double randomWeight =  aDouble* random;
        SortedMap<Double, k> tailMap = this.Map.tailMap(randomWeight, false);
        String k = String.valueOf(this.Map.get(tailMap.firstKey()));
        int o = (Integer) this.nmap.get(k);
        int o2 = (Integer)map.get(k);
        if (o2==o){
            System.out.println("========"+k);
            Map.remove(tailMap.firstKey());

            if (Map.size()==0){
                List collect = map.entrySet().stream().map(java.util.Map.Entry::getKey).collect(Collectors.toList());
                collect.stream().forEach(e->{
                    map.put(String.valueOf(e),0);
                });
                Map.putAll(weightMap);
            }
            k=random();
            return k;
        }
        Integer o1 = (Integer) map.get(k);
        map.put(k,o1+1);
        return k;
    }
}


