package org.nl.acs.device_driver.basedriver.cargo_lift_conveyor;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.nl.acs.agv.server.AgvService;
import org.nl.acs.device.domain.Device;
import org.nl.acs.device.service.DeviceService;
import org.nl.acs.device_driver.DeviceDriver;
import org.nl.acs.device_driver.RouteableDeviceDriver;
import org.nl.acs.device_driver.driver.AbstractOpcDeviceDriver;
import org.nl.acs.device_driver.driver.ExecutableDeviceDriver;
import org.nl.acs.ext.wms.service.AcsToWmsService;
import org.nl.acs.ext.wms.service.impl.AcsToWmsServiceImpl;
import org.nl.acs.instruction.domain.Instruction;
import org.nl.acs.instruction.service.InstructionService;
import org.nl.acs.log.service.DeviceExecuteLogService;
import org.nl.acs.monitor.DeviceStageMonitor;
import org.nl.acs.opc.DeviceAppService;
import org.nl.acs.opc.domain.Opc;
import org.nl.acs.route.service.RouteLineService;
import org.nl.acs.route.service.dto.RouteLineDto;
import org.nl.acs.task.service.TaskService;
import org.nl.acs.task.service.dto.TaskDto;
import org.nl.system.service.param.ISysParamService;
import org.nl.config.SpringContextHolder;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.*;

/**
 * 货梯对接线
 */
@Slf4j
@Data
@RequiredArgsConstructor
public class CargoLiftConveyorDeviceDriver extends AbstractOpcDeviceDriver implements DeviceDriver, ExecutableDeviceDriver, RouteableDeviceDriver, DeviceStageMonitor {

    protected ItemProtocol itemProtocol = new ItemProtocol(this);
    @Autowired
    DeviceAppService deviceAppservice = SpringContextHolder.getBean(DeviceAppService.class);
    @Autowired
    InstructionService instructionService = SpringContextHolder.getBean(InstructionService.class);
    @Autowired
    DeviceService deviceservice = SpringContextHolder.getBean(DeviceService.class);
    @Autowired
    TaskService taskserver = SpringContextHolder.getBean(TaskService.class);
    @Autowired
    RouteLineService routeLineService = SpringContextHolder.getBean(RouteLineService.class);
    @Autowired
    AcsToWmsService acsToWmsService = SpringContextHolder.getBean(AcsToWmsServiceImpl.class);
    @Autowired
    ISysParamService paramService = SpringContextHolder.getBean(ISysParamService.class);
    @Autowired
    DeviceExecuteLogService logServer = SpringContextHolder.getBean(DeviceExecuteLogService.class);
    @Autowired
    AgvService agvService = SpringContextHolder.getBean(AgvService.class);

    private Date instruction_require_time = new Date();
    private Date instruction_finished_time = new Date();
    private Date instruction_apply_time = new Date();
    private int instruction_require_time_out = 3000;

    int heartbeat = 0;
    int mode = 0;
    int move = 0;
    int action = 0;
    int error = 0;
    int task = 0;

    Boolean isonline = true;

    Boolean iserror = false;

    //1-执行任务；2-取货完成；3-放货完成；
    int flag;

    int last_mode = 0;
    int last_move = 0;
    int last_error = 0;

    String device_code;

    @Override
    public Device getDevice() {
        return this.device;
    }

    //请求成功标记
    Boolean requireSucess = false;

    @Override
    public void execute() {
        String message = null;

        device_code = this.getDeviceCode();
        heartbeat = this.itemProtocol.getItem_heartbeat();
        mode = this.itemProtocol.getItem_mode();
        move = this.itemProtocol.getItem_mode();
        error = this.itemProtocol.getItem_error();
        task = this.itemProtocol.getItem_task();
        action = this.itemProtocol.getItem_action();


        if (mode != last_mode) {
            this.setRequireSucess(false);
        }
        if (move != last_move) {
            if (move == 0) {
                thingToNothing();
            }
        }
        if (error != last_error) {
        }


        if (!this.itemProtocol.getIsonline()) {
            this.setIsonline(false);
            this.setIserror(true);
            message = "信号量同步异常";
            //未联机
        } else if (mode == 0) {
            this.setIsonline(false);
            this.setIserror(true);
            message = "未联机";
            //有报警
        } else if (error != 0) {
            this.setIsonline(false);
            this.setIserror(true);
            message = "有报警";
            //无报警
        } else {
            this.setIsonline(true);
            this.setIserror(false);
            message = "";
            Instruction instruction = null;
            List toInstructions;
            switch (mode) {
                case 1:
                    log.debug("设备运转模式:等待工作");
                    break;
                case 2:
                    //申请任务
                    if (move > 0 && !requireSucess) {
                        instruction_require();
                    }
            }
            switch (flag) {
                //取货完成
                case 1:
                    writing(2);
                    break;
                //放货完成
                case 2:
                    writing(3);
                    break;

            }
        }

        last_mode = mode;
        last_move = move;
        last_error = error;
    }


    public synchronized boolean instruction_apply(String container_code) throws Exception {
        Date date = new Date();
        if (date.getTime() - this.instruction_apply_time.getTime() < (long) this.instruction_require_time_out) {
            log.trace("触发时间因为小于{}毫秒，而被无视", this.instruction_require_time_out);
            return false;
        } else {
            this.instruction_apply_time = date;
            requireSucess = true;
            return true;
        }
    }

    public synchronized boolean instruction_require(){
        Date date = new Date();
        if (date.getTime() - this.instruction_require_time.getTime() < (long) this.instruction_require_time_out) {
            log.trace("触发时间因为小于{}毫秒，而被无视", this.instruction_require_time_out);
            return false;
        } else {
            this.instruction_require_time = date;
            //container_code
            TaskDto task = taskserver.queryTaskByDeviceCode(device_code).get(0);
            if (!ObjectUtil.isEmpty(task)) {
                if (!ObjectUtils.isEmpty(instructionService.findByDeviceCodeFromCache(device_code))) {
                    return false;
                }
                String taskid = task.getTask_id();
                String taskcode = task.getTask_code();
                String vehiclecode = task.getVehicle_code();
                String priority = task.getPriority();
                String start_point_code = task.getStart_point_code();
                String start_device_code = task.getStart_device_code();
                String route_plan_code = task.getRoute_plan_code();
                String next_device_code = "";

                /**
                 * 开始平均分配
                 */
                String this_coevice_code = taskserver.queryAssignedByDevice(device_code, task.getNext_device_code());
                if (StrUtil.isEmpty(this_coevice_code)) {
                    List<RouteLineDto> shortPathsList = routeLineService.getShortPathLines(start_device_code, task.getNext_device_code(), route_plan_code);
                    RouteLineDto routeLineDto = shortPathsList.get(0);

                    String path = routeLineDto.getPath();
                    String type = routeLineDto.getType();
                    String[] str = path.split("->");
                    if (!StrUtil.equals(type, "0")) {
                        return false;
                    }
                    List<String> pathlist = Arrays.asList(str);
                    int index = 0;
                    for (int m = 0; m < pathlist.size(); m++) {
                        if (pathlist.get(m).equals(start_device_code)) {
                            index = m + 1;
                            break;
                        }
                    }
                    next_device_code = pathlist.get(index);
                } else {
                    next_device_code = this_coevice_code;
                }
                //校验路由关系
                List<RouteLineDto> shortPathsList = routeLineService.getShortPathLines(start_device_code, next_device_code, route_plan_code);
                if (ObjectUtils.isEmpty(shortPathsList)) {
                    throw new RuntimeException("路由不通!");
                }

                Device startdevice = deviceAppservice.findDeviceByCode(start_device_code);
                Device nextdevice = deviceAppservice.findDeviceByCode(next_device_code);
                String next_point_code;
                if (StrUtil.equals(deviceAppservice.findDeviceTypeByCode(next_device_code), "storage")) {
                    next_point_code = task.getTo_x() + "-" + task.getTo_y() + "-" + task.getTo_z();
                } else {
                    next_point_code = next_device_code;
                }
                Instruction instdto = new Instruction();
                instdto.setInstruction_id(IdUtil.simpleUUID());
                instdto.setRoute_plan_code(route_plan_code);
                instdto.setRemark(task.getRemark());
                instdto.setMaterial(task.getMaterial());
                instdto.setQuantity(task.getQuantity());
                instdto.setTask_id(taskid);
                instdto.setTask_code(taskcode);
                instdto.setVehicle_code(vehiclecode);
                String now = DateUtil.now();
                instdto.setCreate_time(now);
                instdto.setCreate_by("auto");
                instdto.setStart_device_code(start_device_code);
                instdto.setNext_device_code(next_device_code);
                instdto.setStart_point_code(start_point_code);
                instdto.setNext_point_code(next_point_code);
                instdto.setPriority(priority);
                instdto.setInstruction_status("0");
                instdto.setExecute_device_code(start_point_code);
                try {
                    instructionService.create(instdto);
                } catch (Exception e) {
                    e.printStackTrace();
                    log.error("指令创建失败!",e.getMessage());
                    return  false;
                }
                //创建指令后修改任务状态
                task.setTask_status("1");
                taskserver.update(task);
                requireSucess = true;
            }
            return true;
        }
    }

    protected void thingToNothing() {

    }

    public void writing(int command) {
        String to_command = this.getDevice().getOpc_server_code() + "." + this.getDevice().getOpc_plc_code() + "." + this.getDevice().getDevice_code()
                + "." + org.nl.acs.device_driver.basedriver.standard_conveyor_control_with_scanner.ItemProtocol.item_to_command;
        //String opcservcerid = this.getDevice().getOpc_server_id();
//Server server = ReadUtil.getServer(opcservcerid);
        Map<String, Object> itemMap = new HashMap<String, Object>();
        itemMap.put(to_command, command);
        this.control(itemMap);
    }

    public void writing(int type, int command) {
        String to_command = this.getDevice().getOpc_server_code() + "." + this.getDevice().getOpc_plc_code() + "." + this.getDevice().getDevice_code()
                + "." + ItemProtocol.item_to_command;
        String to_target = this.getDevice().getOpc_server_code() + "." + this.getDevice().getOpc_plc_code() + "." + this.getDevice().getDevice_code()
                + "." + ItemProtocol.item_to_target;
        String to_task = this.getDevice().getOpc_server_code() + "." + this.getDevice().getOpc_plc_code() + "." + this.getDevice().getDevice_code()
                + "." + ItemProtocol.item_to_task;
        //String opcservcerid = this.getDevice().getOpc_server_id();
//Server server = ReadUtil.getServer(opcservcerid);
        Map<String, Object> itemMap = new HashMap<String, Object>();
        if (type == 1) {
            itemMap.put(to_command, command);
            log.info("设备:" + device_code + ",下发PLC信号" + to_command + ",value:" + command);
        } else if (type == 2) {
            itemMap.put(to_target, command);
            log.info("设备:" + device_code + ",下发PLC信号" + to_target + ",value:" + command);

        } else if (type == 3) {
            itemMap.put(to_task, command);
            log.info("设备:" + device_code + ",下发PLC信号" + to_task + ",value:" + command);
        }

        this.control(itemMap);
    }

    @Override
    public JSONObject getDeviceStatusName() {
        JSONObject jo = new JSONObject();
        String mode = "";
        String action = "";
        String move = "";
        if (this.getMode() == 0) {
            mode = "未联机";
        } else if (this.getMode() == 1) {
            mode = "单机";
        } else if (this.getMode() == 2) {
            mode = "联机";
        } else if (this.getMode() == 3) {
            mode = "运行中";
        }

        if (this.getAction() == 0) {
            action = "禁止取放";
        } else if (this.getAction() == 1) {
            action = "允许取货";
        } else if (this.getAction() == 2) {
            action = "允许放货";
        } else if (this.getAction() == 3) {
            action = "允许取放";
        }


        if (this.getMove() == 0) {
            move = "无货";
        } else if (this.getMove() == 1) {
            move = "有货";
        } else if (this.getMove() == 2) {
            move = "有托盘有货";
        }
        jo.put("device_name", this.getDevice().getDevice_name());
        jo.put("mode", mode);
        jo.put("move", move);
        jo.put("action", action);
        jo.put("isOnline", this.getIsonline());
        jo.put("error", this.getError());
        jo.put("isError", this.getIserror());
        jo.put("task", this.getTask());
        return jo;
    }

    @Override
    public void setDeviceStatus(JSONObject data) {

    }
}
