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

import cn.hutool.core.util.ObjectUtil;
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.XianGongAgvService;
import org.nl.acs.agv.server.dto.AgvDto;
import org.nl.acs.device.domain.Device;
import org.nl.acs.ext.wms.service.AcsToWmsService;
import org.nl.acs.instruction.domain.Instruction;
import org.nl.acs.log.LokiLog;
import org.nl.acs.log.LokiLogType;
import org.nl.acs.opc.DeviceAppService;
import org.nl.acs.device.enums.DeviceType;
import org.nl.common.exception.BadRequestException;
import org.nl.system.service.param.ISysParamService;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
@Service
@RequiredArgsConstructor
@Lazy
public class XianGongAgvServiceImpl implements XianGongAgvService {
    private final DeviceAppService deviceAppService;
    private final ISysParamService paramService;
    private final AcsToWmsService acsToWmsService;
    Map<String, AgvDto> AGVDeviceStatus = new HashMap();

    @LokiLog(type = LokiLogType.AGV)
    @Override
    public String waitPointRequest(String param) {
        log.info("收到AGV请求参数:{}", param);
        String[] strs = param.split("-");
        String address = strs[0];
        String inst_code = strs[1];
        String type = strs[2];
        String newaddress = null;
        // 前置点会加上p
        if (address.endsWith("IN")) {
            newaddress = address.substring(0, address.length() - 2);
        } else if (address.endsWith("OUT")) {
            newaddress = address.substring(0, address.length() - 3);
        } else if (address.endsWith("P") || address.endsWith("L") || address.endsWith("R")) {
            newaddress = address.substring(0, address.length() - 1);
        } else if (address.endsWith("CZ")) {
            newaddress = address.substring(0, address.length() - 2);
        } else if (address.endsWith("IQ") || address.endsWith("OQ")) {
            newaddress = address.substring(0, address.length() - 2);
        } else {
            newaddress = address;
        }
        boolean is_feedback = false;

        Device device = deviceAppService.findDeviceByCode(newaddress);
        JSONObject jo = new JSONObject();
        if (is_feedback) {
            jo.put("name", param);
            jo.put("lastAction", "wait");
            jo.put("lastActionStatus", "DONE");
            jo.put("status", "IDLE");
        } else {
            jo.put("name", param);
            jo.put("lastAction", "wait");
            jo.put("lastActionStatus", "FAILED");
            jo.put("status", "IDLE");
        }
        is_feedback = false;
        log.info("反馈AGV请求参数:{}", jo.toString());

        return jo.toString();

    }

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

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

            agvurl = agvurl + ":" + agvport + "/api/route/orderSequences/" + 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;
        }


    }

    @LokiLog(type = LokiLogType.AGV)
    @Override
    public HttpResponse queryXZAgvDeviceStatus() {

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

            String agvurl1 = agvurl + ":" + agvport + "/api/route/vehicles";
            String agvurl2 = agvurl + ":" + agvport + "/api/route/vehicleDetails";

            HttpResponse result = HttpRequest.get(agvurl1)
                    .timeout(20000)//超时，毫秒
                    .execute();


            HttpResponse result2 = HttpRequest.get(agvurl2)
                    .timeout(20000)//超时，毫秒
                    .execute();

            System.out.println("查询agv状态数据:" + result.body());
            if (result.getStatus() == 200) {
                JSONArray ja = (JSONArray) JSONArray.parse(result.body());

                for (int i = 0; i < ja.size(); i++) {
                    JSONObject jo = (JSONObject) ja.get(i);
                    String name = jo.getString("name");
                    String state = jo.getString("state");
                    String energyLevel = jo.getString("energyLevel");
                    String transportOrder = jo.getString("transportOrder");
                    JSONObject detailjo = (JSONObject) JSONObject.parse(result2.body());
                    JSONObject item = (JSONObject) detailjo.get(name);
                    String x = item.getString("x");
                    String y = item.getString("y");
                    String angle = item.getString("angle");
                    AgvDto dto = new AgvDto();
                    dto.setName(name);
                    dto.setEnergyLevel(energyLevel);
                    dto.setState(state);
                    dto.setTransportOrder(transportOrder);
                    dto.setPositionAngle(angle);
                    dto.setPositionX(x);
                    dto.setPositionY(y);
                    if (AGVDeviceStatus.containsKey(name)) {
                        AGVDeviceStatus.remove(name);
                        AGVDeviceStatus.put(name, dto);
                    } else {
                        AGVDeviceStatus.put(name, dto);
                    }
                }
            }
            return result;
        } else {
            return null;
        }


    }

    @LokiLog(type = LokiLogType.AGV)
    @Override
    public HttpResponse queryXZAgvInstStatus(String instCode) {

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

            agvurl = agvurl + ":" + agvport + "/api/route/transportOrders/" + instCode;

            HttpResponse result = HttpRequest.get(agvurl)
                    .timeout(20000)//超时，毫秒
                    .execute();
            System.out.println("查询agv指令数据:" + result.body());

            return result;
        } else {

            return null;
        }
    }

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

            agvurl = agvurl + ":" + agvport + "/api/route/transportOrders/" + instCode + "/withdrawal";
            log.info("删除agv指令请求agvurl:{}", agvurl);
            HttpResponse result = HttpRequest.post(agvurl)
                    .timeout(20000)//超时，毫秒
                    .execute();
            log.info("删除agv指令请求反馈:{}", result);
            return result;
        } else {
            return null;
        }
    }

    @LokiLog(type = LokiLogType.AGV)
    @Override
    public HttpResponse sendOrderSequencesToXZ(Instruction inst) throws Exception {
        JSONObject jo = new JSONObject();
        jo.put("intendedVehicle", "");
        jo.put("category", "");
        jo.put("failureFatal", false);
        jo.put("complete", false);
        JSONArray transports = new JSONArray();
        JSONObject orderjo = new JSONObject();
        orderjo.put("name", inst.getInstruction_code());
        orderjo.put("order", createOrederData(inst, "1"));
        transports.add(orderjo);
        jo.put("transports", transports);

        JSONArray ja1 = new JSONArray();
        JSONObject jo1 = new JSONObject();
        jo1.put("key", "");
        jo1.put("value", "");
        ja1.add(jo1);
        jo.put("properties", ja1);

        log.info("任务号：{},指令号{},下发agv订单序列参数:{}", inst.getTask_code(), inst.getInstruction_code(), jo.toString());

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

            agvurl = agvurl + ":" + agvport + "/api/route/orderSequences/" + inst.getTask_code();

            HttpResponse result = HttpRequest.post(agvurl)
                    .body(String.valueOf(jo))//表单内容
                    .timeout(20000)//超时，毫秒
                    .execute();
            log.info(agvurl);
            log.info("任务号：{},指令号{},状态{},下发agv订单序列反馈:{}", inst.getTask_code(), inst.getInstruction_code(), result.getStatus(), result.body());

            return result;
        } else {
            return null;
        }
    }

    @LokiLog(type = LokiLogType.AGV)
    @Override
    public HttpResponse addOrderSequences(Instruction inst) throws Exception {
        JSONObject orderjo = createOrederData(inst, "1");
        log.info("指令号：{},追加agv订单序列参数:{}", inst.getInstruction_code(), orderjo.toString());

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

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

            HttpResponse result = HttpRequest.post(agvurl)
                    .body(String.valueOf(orderjo))//表单内容
                    .timeout(20000)//超时，毫秒
                    .execute();
            log.info(agvurl);
            log.info("任务号：{},指令号{},状态{},追加agv订单序列参数:{}", inst.getTask_code(), inst.getInstruction_code(), result.getStatus(), result.body());

            return result;
        } else {
            return null;
        }
    }

    @LokiLog(type = LokiLogType.AGV)
    @Override
    public String sendOrderSequencesParam(Instruction inst) throws Exception {
        JSONObject jo = new JSONObject();
        jo.put("intendedVehicle", "");
        jo.put("category", "Park");
        jo.put("failureFatal", true);
        jo.put("complete", false);
        JSONArray transports = new JSONArray();
        JSONObject orderjo = createOrederData(inst, "0");
        JSONObject order = new JSONObject();
        orderjo.put("order", order);
        orderjo.put("name", inst.getInstruction_code());
        transports.add(orderjo);
        jo.put("transports", transports);
        return jo.toString();
    }

    @LokiLog(type = LokiLogType.AGV)
    @Override
    public JSONObject createOrederData(Instruction inst, String inst_type) {
        String inst_code = inst.getInstruction_code();
        String task_code = inst.getTask_code();
        String compound_inst_data = inst.getCompound_inst_data();
        String[] str = null;
        List<String> pathlist = null;
        if (!StrUtil.isEmpty(compound_inst_data)) {
            str = compound_inst_data.split("->");
            pathlist = Arrays.asList(str);
        }
        JSONArray ja = new JSONArray();
        JSONObject orderjo = new JSONObject();

        //1表示追加任务，需将task_code赋值给wrappingSequence
        if (StrUtil.equals("1", inst_type)) {
            orderjo.put("wrappingSequence", task_code);
        }
        String instno = inst.getInstruction_code();
        //指定agv车号 暂时不用
        //orderjo.put("intendedVehicle", "");
        //设置任务最终时间
        orderjo.put("deadline", AgvUtil.getNextDay(1));
        orderjo.put("category", "");
        //拼接起点子任务动作，待完善，动作码需要从数据库取值
        int type = Integer.parseInt(paramService.findByCode(AcsConfig.BUSINESSTYPE).getValue());

        switch (type) {
            case 3:
                break;
            case 4:
                break;
            case 6:
                String startAddress = inst.getStart_device_code();
                String nextAddress = inst.getNext_device_code();
                Device startdevice = deviceAppService.findDeviceByCode(startAddress);
                Device nextdevice = deviceAppService.findDeviceByCode(nextAddress);

                break;
        }

        orderjo.put("destinations", ja);
        JSONObject prijo = new JSONObject();
        prijo.put("key", "duration");
        prijo.put("value", "101");

        JSONArray prija = new JSONArray();
        prija.add(prijo);
        orderjo.put("properties", prija);

        return orderjo;
    }


    /**
     * 返回一个点位操作子任务  先知使用
     *
     * @param locationName   点位
     * @param operation      点位操作
     * @param propertiesType 子任务类型
     * @param pro            子任务参数
     *                       调用demo:destination("sh15p", "Spin", "2", "3.14")
     *                       demo:destination("cz14", "JackUnload", "3", "")
     * @return
     */

    public static JSONObject destination2(String locationName, String operation, String propertiesType, String pro) {

        //新增业务订单
        JSONObject destinationOrder = new JSONObject();
        //目标工作站
        destinationOrder.put("locationName", locationName);
        //机器人在工作站要执行的操作
        destinationOrder.put("operation", operation);
        if (propertiesType.equals("1")) {//Wait请求是否继续
            JSONArray properties = new JSONArray();
            JSONObject pro2 = new JSONObject();
            pro2.put("key", "device:queryAtExecuted");//固定值
            pro2.put("value", pro + ":wait");//pro为wait请求的标识，一般用点位拼接的字符串
            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")) {//Wait请求是否继续
            JSONArray properties = new JSONArray();
            JSONObject pro2 = new JSONObject();

            destinationOrder.put("properties", "[]");
        }
        return destinationOrder;
    }

    @LokiLog(type = LokiLogType.AGV)
    @Override
    public String queryDoorStatus(String device) {
        log.info("AGV查询自动门状态,参数：{}", device);
        int type = Integer.parseInt(paramService.findByCode(AcsConfig.BUSINESSTYPE).getValue());
        switch (type) {
            case 4:
                if (StrUtil.equals(paramService.findByCode(AcsConfig.HASOTHERSYSTEM).getValue(), "1")) {
                    String result = acsToWmsService.queryDoorsStatus().body();
                    JSONArray ja = JSONArray.parseArray(result);
                    log.info("AGV查询自动门状态,反馈：{}", ja.toString());
                    return ja.toString();
                }
                return null;
            default:
                if (StrUtil.equals("doors", device)) {
                    List<Device> list = deviceAppService.findDevice(DeviceType.autodoor);
                    JSONArray ja = new JSONArray();
                    for (int i = 0; i < list.size(); i++) {
                        Device doordevice = deviceAppService.findDeviceByCode(list.get(i).getDevice_code());
                        if (ObjectUtil.isEmpty(doordevice)) {
                            throw new BadRequestException("未找到对应设备");
                        }
                        String mes = null;
                        JSONObject jo = JSONObject.parseObject(mes);
                        ja.add(jo);
                    }
                    log.info("AGV查询自动门状态,反馈：{}", ja.toString());
                    return ja.toString();

                } else {
                    Device doordevice = deviceAppService.findDeviceByCode(device);
                    if (ObjectUtil.isEmpty(doordevice)) {
                        throw new BadRequestException("未找到对应设备");
                    }
                    String mes = null;
                    JSONObject jo = JSONObject.parseObject(mes);
                    log.info("AGV查询自动门状态,反馈：{}", jo.toString());
                    return jo.toString();
                }
        }

    }

    @Override
    public Map<String, AgvDto> findAllAgvFromCache() {
        return AGVDeviceStatus;
    }

}
