package org.nl.acs.agv.server.impl;

import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.nl.acs.AcsConfig;
import org.nl.acs.agv.AgvUtil;
import org.nl.acs.agv.server.ZheDaAgvService;
import org.nl.acs.device.domain.Device;
import org.nl.acs.device.service.DeviceService;
import org.nl.acs.device.service.dto.DeviceDto;
import org.nl.acs.device_driver.basedriver.cargo_lift_conveyor.CargoLiftConveyorDeviceDriver;
import org.nl.acs.device_driver.basedriver.empty_vehicle_stacking_position.EmptyVehicleStackingPositionDeviceDriver;
import org.nl.acs.device_driver.basedriver.hailiang_smart_plc_test.HailiangSmartplcTestDeviceDriver;
import org.nl.acs.device_driver.basedriver.hongxiang_device.HongXiangConveyorDeviceDriver;
import org.nl.acs.device_driver.basedriver.paint_conveyor.PaintConveyorDeviceDriver;
import org.nl.acs.device_driver.tianneng.site.SiteDeviceDriver;
import org.nl.acs.ext.wms.service.AcsToWmsService;
import org.nl.acs.instruction.domain.Instruction;
import org.nl.acs.instruction.service.InstructionService;
import org.nl.acs.log.LokiLog;
import org.nl.acs.log.LokiLogType;
import org.nl.acs.opc.DeviceAppService;
import org.nl.acs.opc.DeviceAppServiceImpl;
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.stereotype.Service;

import javax.annotation.Resource;

@Slf4j
@Service
@RequiredArgsConstructor
public class ZheDaAgvServiceImpl implements ZheDaAgvService {
    private final ISysParamService paramService;
    private final InstructionService instructionService;
    private final DeviceService deviceService;
    private final DeviceAppService deviceAppService;
    @LokiLog(type = LokiLogType.AGV)
    @Override
    public HttpResponse sendAgvInstToAgv(Instruction inst) throws Exception {
        JSONObject jo = new JSONObject();
        DeviceDto startDevice= deviceService.findByCode(inst.getStart_point_code());
        String start_point_code = startDevice.getRemark();
        DeviceDto nextDevice= deviceService.findByCode(inst.getNext_point_code());
        String next_point_code = nextDevice.getRemark();
        //1楼AGV普通任务
        //2楼AGV普通任务
        //2楼AGV起点追加任务
        //2楼AGV终点追加任务
        String task_type = inst.getInstruction_type();
        jo.put("deadline", AgvUtil.getNextDay(1));
        //判断是否追加任务
        if (task_type.equals("3") || task_type.equals("4")) {
            jo.put("complete", "false");
        } else {
            jo.put("complete", "true");
        }
        jo.put("task_code", inst.getInstruction_code());
        //根据任务，下发指令类型
        JSONArray destinations = new JSONArray();
        if (task_type.equals("3")) {
            destinations.add(destination(start_point_code, "Wait", "5", "1"));
        } else if (task_type.equals("4")) {
            destinations.add(destination(start_point_code, "Load", "1", "1"));
            destinations.add(destination(next_point_code, "Wait", "5", "1"));
        } else {
            destinations.add(destination(start_point_code, "Load", "1", "3"));
            destinations.add(destination(next_point_code, "Unload", "1", "1"));
        }

        jo.put("destinations", destinations);

        if (StrUtil.equals(paramService.findByCode(AcsConfig.FORKAGV).getValue(), "1")) {
            String agvurl = paramService.findByCode(AcsConfig.RGVURL).getValue();
            String agvport = paramService.findByCode(AcsConfig.RGVPORT).getValue();

            agvurl = agvurl + ":" + agvport + "/transportOrders/" + inst.getInstruction_code();

            log.info("下发agv任务请求:{}内容为：{}", agvurl,String.valueOf(jo));

            HttpResponse result = HttpRequest.post(agvurl)
                    .body(String.valueOf(jo))//表单内容
                    .timeout(20000)//超时，毫秒
                    .execute();
            log.info("下发agv任务请求反馈:{}", result);
            return result;
        } else {
            return null;
        }
    }

    @LokiLog(type = LokiLogType.AGV)
    @Override
    //ZDAGV
    public HttpResponse queryAgvInstStatus(String type) {
        if (StrUtil.equals(paramService.findByCode(AcsConfig.FORKAGV).getValue(), "1")) {
            String agvurl = "";
            String agvport = "";

            agvurl = paramService.findByCode(AcsConfig.RGVURL).getValue();
            agvport = paramService.findByCode(AcsConfig.RGVPORT).getValue();

            agvurl = agvurl + ":" + agvport + "/transportOrders/query";
            log.info("下发agv查询状态请求:{}内容为：{}", agvurl);
            HttpResponse result = HttpRequest.post(agvurl)
                    .body(String.valueOf(new JSONObject()))//表单内容
                    .timeout(20000)//超时，毫秒
                    .execute();
            log.info("查询agv指令数据:" + result.body());

            return result;
        } else {
            return null;
        }
    }

    @LokiLog(type = LokiLogType.AGV)
    @Override
    //ZDAGV
    public HttpResponse queryAgvDeviceStatus(String type) {
        if (StrUtil.equals(paramService.findByCode(AcsConfig.FORKAGV).getValue(), "1")) {
            String agvurl = "";
            String agvport = "";

            agvurl = paramService.findByCode(AcsConfig.RGVURL).getValue();
            agvport = paramService.findByCode(AcsConfig.RGVPORT).getValue();

            agvurl = agvurl + ":" + agvport + "/vehicles";
            log.info("下发agv查询设备状态请求:{}内容为：{}", agvurl);
            HttpResponse result = HttpRequest.post(agvurl)
                    .body(String.valueOf(new JSONObject()))//表单内容
                    .timeout(20000)//超时，毫秒
                    .execute();
            log.info("查询agv设备数据:" + result.body());

            return result;
        } else {
            return null;
        }
    }
    @LokiLog(type = LokiLogType.AGV)
    @Override
    //ZDAGV
    public synchronized String process(String jobno, String type, String address, String action, String processingVehicle) {
        log.info("查询到AGV请求参数,jobno:{},address:{}", jobno + ",address:" + address + ",type:" + type + ",action:" + action);
        //释放AGV资源，继续后续动作
        boolean is_feedback = false;
        String str = "";
        String backaddress = address;
        if (address.indexOf(".") > 0) {
            str = address.substring(address.indexOf(".") + 1, address.length());
            address = address.substring(0, address.indexOf("."));
        } else if (address.indexOf("-") > 0) {
            address = address.substring(0, address.indexOf("-"));
        }
        InstructionService instructionService = SpringContextHolder.getBean("instructionServiceImpl");
        TaskService taskService = SpringContextHolder.getBean("taskServiceImpl");
        AcsToWmsService acsToWmsService = SpringContextHolder.getBean("acsToWmsServiceImpl");

        Instruction inst = instructionService.findByCodeFromCache(jobno);
        TaskDto task = taskService.findByCode(inst.getTask_code());

        DeviceAppService appService = SpringContextHolder.getBean(DeviceAppServiceImpl.class);
        Device addressdevice = appService.findDeviceByCode(address);

        CargoLiftConveyorDeviceDriver cargoLiftConveyorDeviceDriver;
        EmptyVehicleStackingPositionDeviceDriver emptyVehicleStackingPositionDeviceDriver;
        HailiangSmartplcTestDeviceDriver hailiangSmartplcTestDeviceDriver;
        HongXiangConveyorDeviceDriver hongXiangConveyorDeviceDriver;
        PaintConveyorDeviceDriver paintConveyorDeviceDriver;

        //取货的进入前等待和离开等待
        if (action.equals("Load")) {
            if ("EntryRequired".equals(type)) {

            }
            if ("PauseOnStation".equals(type)) {
                String startPoint=inst.getStart_point_code();
                Device start_device = deviceAppService.findDeviceByCode(startPoint);
                if (start_device.getDeviceDriver() instanceof SiteDeviceDriver) {
                    SiteDeviceDriver siteDeviceDriver=(SiteDeviceDriver)start_device.getDeviceDriver();
                    if(siteDeviceDriver.getMode()!=10) {
                        try {
                            siteDeviceDriver.writing(10);
                            siteDeviceDriver.writing(10);
                            siteDeviceDriver.writing(10);
                            siteDeviceDriver.writing(10);
                            siteDeviceDriver.writing(10);
                        }catch(Exception e){
                            log.error("写入信号失败：{}{}",e,e.getMessage());
                        }
                    }
                }
                is_feedback = true;
            }
        }
        //等待点等待
        if (action.equals("Wait")) {
            if ("Wait".equals(type)) {
                JSONObject jo = new JSONObject();
                jo.put("task_code", inst.getInstruction_code());
                JSONArray destinations = new JSONArray();
                String inst_type = inst.getInstruction_type();

                String resp = acsToWmsService.requestTaskAgain(address,task.getExt_task_id(),inst.getVehicle_code());
                JSONObject respjson = JSONObject.parseObject(resp);


                String next_device_code = respjson.getString("next_point_code");
                DeviceDto device= deviceService.findByCode(next_device_code);

                destinations.add(destination(device.getRemark(), "Unload", "1", "1"));

                jo.put("destinations", destinations);

                String agvurl = paramService.findByCode(AcsConfig.RGVURL).getValue();
                String agvport = paramService.findByCode(AcsConfig.RGVPORT).getValue();

                String url = agvurl + ":" + agvport + "/addDestinations";
                log.info("下发agv任务请求:{}", url);

                HttpResponse result = HttpRequest.post(url)
                        .body(String.valueOf(jo))//表单内容
                        .timeout(20000)//超时，毫秒
                        .execute();
                log.info("下发agv任务请求反馈:{}", result);

                //对任务进行封口
                JSONObject complete = new JSONObject();
                complete.put("task_code", inst.getInstruction_code());

                String url2 = agvurl + ":" + agvport + "/markComplete";
                log.info("下发agv任务请求:{}", url2);

                HttpResponse result2 = HttpRequest.post(url2)
                        .body(String.valueOf(complete))//表单内容
                        .timeout(20000)//超时，毫秒
                        .execute();
                log.info("下发agv任务请求反馈:{}", result2);
            }
        }
        //放货的进入前等待和离开等待
        if (action.equals("Unload")) {
            if ("EntryRequired".equals(type)) {

            }
            if ("PauseOnStation".equals(type)) {

                JSONObject jo = new JSONObject();
                jo.put("task_code", inst.getInstruction_code());
                JSONArray destinations = new JSONArray();

                String resp = acsToWmsService.requestTaskAgain(address,task.getExt_task_id(),inst.getVehicle_code());
                JSONObject respjson = JSONObject.parseObject(resp);


                String next_device_code = respjson.getString("next_point_code");
                DeviceDto device= deviceService.findByCode(next_device_code);

                destinations.add(destination(device.getRemark(), "Unload", "1", "1"));

                jo.put("destinations", destinations);

                String agvurl = paramService.findByCode(AcsConfig.RGVURL).getValue();
                String agvport = paramService.findByCode(AcsConfig.RGVPORT).getValue();

                String url = agvurl + ":" + agvport + "/addDestinations";
                log.info("下发agv任务请求:{}", url);

                HttpResponse result = HttpRequest.post(url)
                        .body(String.valueOf(jo))//表单内容
                        .timeout(20000)//超时，毫秒
                        .execute();
                log.info("下发agv任务请求反馈:{}", result);

                //对任务进行封口
                JSONObject complete = new JSONObject();
                complete.put("task_code", inst.getInstruction_code());

                String url2 = agvurl + ":" + agvport + "/markComplete";
                log.info("下发agv任务请求:{}", url2);

                HttpResponse result2 = HttpRequest.post(url2)
                        .body(String.valueOf(complete))//表单内容
                        .timeout(20000)//超时，毫秒
                        .execute();
                log.info("下发agv任务请求反馈:{}", result2);
            }

        }
        JSONObject requestjo = new JSONObject();
        if (is_feedback) {
            requestjo.put("task_code", jobno);
            requestjo.put("operation", action);
            if (type.equals("entryRequired") || type.equals("EntryRequired")) {
                requestjo.put("entryRequired", "true");
            } else {
                requestjo.put("pauseOnStation", "true");
            }
            log.info("反馈AGV请求数据:{}", requestjo);
            System.out.println("back agv:" + requestjo);

            String agvurl = paramService.findByCode(AcsConfig.RGVURL).getValue();
            String agvport = paramService.findByCode(AcsConfig.RGVPORT).getValue();
            agvurl = agvurl + ":" + agvport + "/transportOrders/" + jobno + "/interact";

            HttpResponse result = HttpRequest.post(agvurl)
                    .body(String.valueOf(requestjo))
                    .timeout(20000)//超时，毫秒
                    .execute();
        }
        return requestjo.toString();

    }
    @LokiLog(type = LokiLogType.AGV)
    @Override
    public HttpResponse markComplete(String code) {

        if (StrUtil.equals(paramService.findByCode(AcsConfig.FORKAGV).getValue(), "1")) {
            String agvurl = paramService.findByCode(AcsConfig.RGVURL).getValue();
            String agvport = paramService.findByCode(AcsConfig.RGVPORT).getValue();

            agvurl = agvurl + ":" + agvport + "/" + code + "/markComplete";
            log.info("关闭agv运单序列请求:{}", agvurl);

            HttpResponse result = HttpRequest.post(agvurl)
                    //.body(String.valueOf(orderjo))//表单内容
                    .timeout(20000)//超时，毫秒
                    .execute();
            log.info("关闭agv运单序列请求反馈:{}", result);

            return result;
        } else {
            return null;
        }

    }


    /**
     * 返回一个点位操作子任务
     *
     * @param locationName   点位
     * @param operation      点位操作
     * @param propertiesType 子任务类型
     * @param pro            子任务参数
     *                       调用demo:destination("sh15p", "Spin", "2", "3.14")
     *                       demo:destination("cz14", "JackUnload", "3", "")
     * @return
     */
    //ZDAGV
    @LokiLog(type = LokiLogType.AGV)
    public static JSONObject destination(String locationName, String operation, String propertiesType, String pro) {
        //新增业务订单
        JSONObject destinationOrder = new JSONObject();
        //目标工作站
        destinationOrder.put("locationName", locationName);
        //机器人在工作站要执行的操作
        destinationOrder.put("operation", operation);
        if (propertiesType.equals("1")) {//取货前等待、取货后等待

            //pro 1  进入离开等待
            if ("1".equals(pro)) {
                JSONArray properties = new JSONArray();
                JSONObject pro1 = new JSONObject();
                pro1.put("key", "EntryRequired");
                pro1.put("value", "True");
                properties.add(pro1);
                JSONObject pro2 = new JSONObject();
                pro2.put("key", "PauseOnStation");
                pro2.put("value", "True");
                properties.add(pro2);
                destinationOrder.put("properties", properties);
                //进入等待 离开不等待
            } else if ("2".equals(pro)) {
                JSONArray properties = new JSONArray();
                JSONObject pro1 = new JSONObject();
                pro1.put("key", "EntryRequired");
                pro1.put("value", "True");
                properties.add(pro1);
                JSONObject pro2 = new JSONObject();
                pro2.put("key", "PauseOnStation");
                pro2.put("value", "False");
                properties.add(pro2);
                destinationOrder.put("properties", properties);
                //进入不等待 离开等待
            } else if ("3".equals(pro)) {
                JSONArray properties = new JSONArray();
                JSONObject pro1 = new JSONObject();
                pro1.put("key", "EntryRequired");
                pro1.put("value", "False");
                properties.add(pro1);
                JSONObject pro2 = new JSONObject();
                pro2.put("key", "PauseOnStation");
                pro2.put("value", "True");
                properties.add(pro2);
                destinationOrder.put("properties", properties);
                //不等待
            } else {
                JSONArray properties = new JSONArray();
                JSONObject pro1 = new JSONObject();
                pro1.put("key", "EntryRequired");
                pro1.put("value", "False");
                properties.add(pro1);
                JSONObject pro2 = new JSONObject();
                pro2.put("key", "PauseOnStation");
                pro2.put("value", "False");
                properties.add(pro2);
                destinationOrder.put("properties", properties);
            }

        } else if (propertiesType.equals("2")) {//Spin转动
            JSONArray properties = new JSONArray();
            JSONObject pro1 = new JSONObject();
            pro1.put("key", "global_spin_angle");//坐标系类型，global_spin_angle为全局坐标系
            pro1.put("value", pro);//弧度值，如3.14
            properties.add(pro1);
            JSONObject pro2 = new JSONObject();
            pro2.put("key", "spin_direction");//固定值
            pro2.put("value", "0");//弧度值，如0
            properties.add(pro2);
            destinationOrder.put("properties", properties);
        } else if (propertiesType.equals("3")) {//JackUnload,Jackload不操作
            JSONArray properties = new JSONArray();
            JSONObject pro1 = new JSONObject();
            pro1.put("key", "recognize");//固定值
            pro1.put("value", "false");//固定值
            properties.add(pro1);
            destinationOrder.put("properties", properties);
        } else if (propertiesType.equals("4")) {
            JSONArray properties = new JSONArray();
            JSONObject pro1 = new JSONObject();
            pro1.put("key", "robot_spin_angle");//坐标系类型，robot_spin_angle为机器人坐标系
            pro1.put("value", pro);//弧度值，如3.14
            properties.add(pro1);
            JSONObject pro2 = new JSONObject();
            pro2.put("key", "spin_direction");//固定值
            pro2.put("value", "0");//弧度值，如0
            properties.add(pro2);
            destinationOrder.put("properties", properties);
        } else if (propertiesType.equals("5")) {//在该点进行等待
            JSONArray properties = new JSONArray();
            JSONObject pro1 = new JSONObject();
            pro1.put("key", "Wait");
            pro1.put("value", "True");
            properties.add(pro1);
            destinationOrder.put("properties", properties);
        }
        return destinationOrder;
    }

    @LokiLog(type = LokiLogType.AGV)
    @Override
    public HttpResponse deleteZDAgvInst(String instCode)  throws Exception {
        if (StrUtil.equals(paramService.findByCode(AcsConfig.FORKAGV).getValue(), "1")) {
            String agvurl = paramService.findByCode(AcsConfig.RGVURL).getValue();
            String agvport = paramService.findByCode(AcsConfig.RGVPORT).getValue();
            Instruction instruction = instructionService.findByCode(instCode);
            agvurl = agvurl + ":" + agvport + "/transportOrders/" + instCode + "/withdrawal";
            log.info("删除agv指令请求agvurl:{}", agvurl);
            HttpResponse result = HttpRequest.post(agvurl)
                    .body("{}")
                    .timeout(20000)//超时，毫秒
                    .execute();
            log.info("删除agv指令请求反馈:{}", result);
            return result;
        } else {
            return null;
        }
    }

}
