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

import cn.hutool.core.util.StrUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.nl.acs.AcsConfig;
import org.nl.acs.agv.server.NDCAgvService;
import org.nl.acs.agv.server.dto.AgvDto;
import org.nl.acs.auto.run.OneNDCSocketConnectionAutoRun;
import org.nl.acs.device.service.DeviceService;
import org.nl.acs.device.service.impl.DeviceServiceImpl;
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.log.service.DeviceExecuteLogService;
import org.nl.acs.opc.DeviceAppService;
import org.nl.acs.opc.DeviceAppServiceImpl;
import org.nl.system.service.dict.ISysDictService;
import org.nl.system.service.dict.dao.Dict;
import org.nl.system.service.param.ISysParamService;
import org.nl.common.utils.CodeUtil;
import org.nl.config.SpringContextHolder;
import org.nl.system.service.param.ISysParamService;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

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

@Slf4j
@Service
@RequiredArgsConstructor
@Lazy
public class NDCAgvServiceImpl implements NDCAgvService {

    private final DeviceAppService deviceAppService;
    private final ISysParamService paramService;
    private final AcsToWmsService acsToWmsService;
    private final ISysDictService dictService;

    private final DeviceExecuteLogService logServer;

    Map<String, AgvDto> AGVDeviceStatus = new HashMap();

    @LokiLog(type = LokiLogType.AGV)
    @Override
    public void deleteAgvInstToNDC(Instruction inst) throws Exception {
        if (StrUtil.equals(paramService.findByCode(AcsConfig.FORKAGV).getValue(), "1")) {
            int index = Integer.parseInt(inst.getAgv_jobno());

            byte indexhigh = (byte) IntToHexHigh(index);
            byte indexlow = (byte) IntToHexLow(index);

            String str = "十进制下发：";
            String str1 = "十六进制下发：";
            str += "index:" + index;
            str1 += "ikey:" + hexToString(indexhigh & 0xFF) + hexToString(indexlow & 0xFF);
            System.out.println(str);
            System.out.println(str1);

            byte[] b = new byte[]{(byte) 0X87, (byte) 0XCD,
                    (byte) 0X00, (byte) 0X08,
                    (byte) 0X00, (byte) 0X06,
                    (byte) 0X00, (byte) 0X01,
                    (byte) 0X00, (byte) 0X6E,
                    (byte) 0X00, (byte) 0X02,
                    (byte) indexhigh, (byte) indexlow,
            };
            log.info("下发删除AGV指令--{}", Bytes2HexString(b));

            OneNDCSocketConnectionAutoRun.write(b);
            System.out.println("下发删除agv指令数据:" + Bytes2HexString(b));
        }

    }


    @LokiLog(type = LokiLogType.AGV)
    @Override
    public void sendAgvInstToNDC(String agv_system_type, Instruction inst) {
        if (StrUtil.equals(paramService.findByCode(AcsConfig.FORKAGV).getValue(), "1")) {
            String instcode = inst.getInstruction_code();
            int type = Integer.parseInt(inst.getInstruction_type());
            int priority = Integer.parseInt(inst.getPriority()) + 128;
            DeviceAppService appService = SpringContextHolder.getBean(DeviceAppServiceImpl.class);
            DeviceService deviceService = SpringContextHolder.getBean(DeviceServiceImpl.class);
            int startAddress = deviceService.queryAddressBydeviceCode(inst.getStart_point_code());
            int nextAddress=deviceService.queryAddressBydeviceCode(inst.getNext_point_code());
            byte ikeyhigh = (byte) IntToHexHigh(Integer.parseInt(instcode));
            byte ikeylow = (byte) IntToHexLow(Integer.parseInt(instcode));
            byte typehigh = (byte) IntToHexHigh(Integer.parseInt(inst.getInstruction_type()));
            byte typelow = (byte) IntToHexLow(Integer.parseInt(inst.getInstruction_type()));
            byte qhdhigh = (byte) IntToHexHigh(startAddress);
            byte qhdlow = (byte) IntToHexLow(startAddress);
            byte fhdhigh = (byte) IntToHexHigh(nextAddress);
            byte fhdlow = (byte) IntToHexLow(nextAddress);
            byte prioritylow = (byte) IntToHexLow(priority);
            String str = "十进制下发：";
            String str1 = "十六进制下发：";
            str += "ikey:" + (Integer.parseInt(instcode));
            str1 += "ikey:" + hexToString(ikeyhigh & 0xFF) + hexToString(ikeylow & 0xFF);
            str += "/type:" + (type);
            str1 += "/type:" + hexToString(typehigh & 0xFF) + hexToString(typelow & 0xFF);
            str += "/qhd:" + (startAddress);
            str1 += "/qhd:" + hexToString(qhdhigh & 0xFF) + hexToString(qhdlow & 0xFF);
            str += "/fhd:" + (nextAddress);
            str1 += "/fhd:" + hexToString(fhdhigh & 0xFF) + hexToString(fhdlow & 0xFF);
            str += "/priority:" + (priority);
            str1 += "/priority:" + hexToString(prioritylow & 0xFF);
            System.out.println(str);
            System.out.println(str1);
            byte[] b = new byte[]{(byte) 0X87, (byte) 0XCD,
                    (byte) 0X00, (byte) 0X08,
                    (byte) 0X00, (byte) 0X12,
                    (byte) 0X00, (byte) 0X01,
                    (byte) 0X00, (byte) 0X71,
                    (byte) 0X00, (byte) 0X0E,
                    //任务优先级，80无优先级
                    (byte) 0X01, prioritylow,
                    (byte) 0X00, (byte) 0X01,
                    //任务单号
                    (byte) ikeyhigh, (byte) ikeylow,
                    //重复任务单号
                    (byte) ikeyhigh, (byte) ikeylow,
                    //任务类型
                    (byte) typehigh, (byte) typelow,
                    //起点
                    (byte) qhdhigh, (byte) qhdlow,
                    //终点
                    (byte) fhdhigh, (byte) fhdlow
            };
            log.info("下发AGV作业指令--{}", str1);
            OneNDCSocketConnectionAutoRun.write(b);
            System.out.println("下发agv指令数据:" + Bytes2HexString(b));
        }
    }

    @Override
    public byte[] sendAgvOneModeInst(int phase, int index, int result) {
        if (phase < 0 || index < 0)
        {  return null;}
        byte indexhigh = (byte) IntToHexHigh(index);
        byte indexlow = (byte) IntToHexLow(index);
        byte phasehigh = (byte) IntToHexHigh(phase);
        byte phaselow = (byte) IntToHexLow(phase);
        byte[] b = new byte[]{(byte) 0X87, (byte) 0XCD,
                (byte) 0X00, (byte) 0X08,
                (byte) 0X00, (byte) 0X0A,
                (byte) 0X00, (byte) 0X01,
                (byte) 0X00, (byte) 0X6D,
                (byte) 0X00, (byte) 0X06,
                //agv任务号，agv任务主键
                (byte) indexhigh, (byte) indexlow,
                (byte) 0X01, (byte) 0X12,
                //Phase的值，即NDC请求的阶段可以运行了
                (byte) phasehigh, (byte) phaselow
        };

        log.info("反馈agv动作数据--index:" + hexToString(indexhigh & 0xFF) + hexToString(indexlow & 0xFF) + ",phase:" + hexToString(phasehigh & 0xFF) + hexToString(phaselow & 0xFF));

        System.out.println("反馈agv动作数据:" + Bytes2HexString(b));
        return b;

    }

    @Override
    public byte[] sendAgvOneModeInst(int phase, int index, int result,int startPoint,int nextPoint,int startHigh,int nextHigh) {
        if (phase < 0 || index < 0)
            return null;
        byte indexhigh = (byte) IntToHexHigh(index);
        byte indexlow = (byte) IntToHexLow(index);
        byte phasehigh = (byte) IntToHexHigh(phase);
        byte phaselow = (byte) IntToHexLow(phase);
        byte startPointHigh =(byte) IntToHexHigh(startPoint);
        byte startPointLow =(byte) IntToHexLow(startPoint);
        byte nextPointHigh =(byte) IntToHexHigh(nextPoint);
        byte nextPointLow =(byte) IntToHexLow(nextPoint);
        byte startHighHigh =(byte) IntToHexHigh(startHigh);
        byte startHighLow =(byte) IntToHexLow(startHigh);
        byte nextHighHigh =(byte) IntToHexHigh(nextHigh);
        byte nextHighLow =(byte) IntToHexLow(nextHigh);

        byte[] b = new byte[]{(byte) 0X87, (byte) 0XCD,
                (byte) 0X00, (byte) 0X08,
                (byte) 0X00, (byte) 0X0C,
                (byte) 0X00, (byte) 0X01,
                (byte) 0X00, (byte) 0X6D,
                (byte) 0X00, (byte) 0X08,
                (byte) indexhigh, (byte) indexlow,
                (byte) 0X01, (byte) 0X12,
                (byte) phasehigh, (byte) phaselow,
                (byte) nextPointHigh,(byte) nextPointLow
        };

        log.info("反馈agv动作数据--index:" + hexToString(indexhigh & 0xFF) + hexToString(indexlow & 0xFF) + ",phase:" + hexToString(phasehigh & 0xFF) + hexToString(phaselow & 0xFF));

        System.out.println("反馈agv动作数据:" + Bytes2HexString(b));
        return b;

    }


    @Override
    public byte[] sendAgvTwoModeInst(int phase, int index, int result) {

        if (phase < 0 || index < 0)
            return null;
        byte indexhigh = (byte) IntToHexHigh(index);
        byte indexlow = (byte) IntToHexLow(index);
        byte phasehigh = (byte) IntToHexHigh(phase);
        byte phaselow = (byte) IntToHexLow(phase);

        byte[] b = new byte[]{(byte) 0X87, (byte) 0XCD,
                (byte) 0X00, (byte) 0X08,
                (byte) 0X00, (byte) 0X0A,
                (byte) 0X00, (byte) 0X01,
                (byte) 0X00, (byte) 0X6D,
                (byte) 0X00, (byte) 0X06,
                (byte) indexhigh, (byte) indexlow,
                (byte) 0X01, (byte) 0X10,
                (byte) phasehigh, (byte) phaselow
        };


        log.info("反馈agv动作数据--index:" + hexToString(indexhigh & 0xFF) + hexToString(indexlow & 0xFF) + ",phase:" + hexToString(phasehigh & 0xFF) + hexToString(phaselow & 0xFF));

        System.out.println("反馈agv动作数据:" + Bytes2HexString(b));
        return b;
    }
    @Override
    public void charge(String carno) {
        //检查数据字典station为0的参数
        //分配车辆
        List<Dict> dictList= dictService.getDictByName("station");
        int satation=0;
        Dict temp=new Dict();
        for(Dict dict : dictList){
            if ("1".equals(dict.getValue())&&carno.equals(dict.getPara2())){
                log.info("当前车辆{}已分配充电桩{}，退出后续判断",carno,dict.getPara1());
                return;
            }
        }
        for(Dict dict : dictList){
            if ("0".equals(dict.getValue())){
                satation = Integer.parseInt(dict.getPara1());
                temp=dict;
                break;
            }
        }
        if(satation!=0){
            String instcode =CodeUtil.getNewCode("INSTRUCT_NO");
            byte ikeyhigh = (byte) IntToHexHigh(Integer.parseInt(instcode));
            byte ikeylow = (byte) IntToHexLow(Integer.parseInt(instcode));
            byte carhigh = (byte) IntToHexHigh(Integer.parseInt(carno));
            byte carlow = (byte) IntToHexLow(Integer.parseInt(carno));
            byte satationhigh = (byte) IntToHexHigh(satation);
            byte satationlow = (byte) IntToHexLow(satation);
            String str = "十进制下发：";
            String str1 = "十六进制下发：";
            str += "ikey:" + (Integer.parseInt(instcode));
            str1 += "ikey:" + hexToString(ikeyhigh & 0xFF) + hexToString(ikeylow & 0xFF);
            str += "carno:" + (Integer.parseInt(carno));
            str1 += "carno:" + hexToString(carhigh & 0xFF) + hexToString(carlow & 0xFF);
            str += "/satation:" + (satation);
            str1 += "/satation:" + hexToString(satationhigh & 0xFF) + hexToString(satationlow & 0xFF);
            //todo 核对NDC协议
            byte[] b = new byte[]{(byte) 0X87, (byte) 0XCD,
                    (byte) 0X00, (byte) 0X08,
                    (byte) 0X00, (byte) 0X0E,
                    (byte) 0X00, (byte) 0X01,
                    (byte) 0X00, (byte) 0X71,
                    (byte) 0X00, (byte) 0X0A,
                    (byte) 0X64, (byte) 0X80,
                    (byte) 0X00, (byte) 0X01,
                    (byte) ikeyhigh, (byte) ikeylow,
                    (byte) carhigh, (byte) carlow,
                    (byte) satationhigh, (byte) satationlow

            };
            log.info("下发AGV充电任务--{}", str1);

            try{
                OneNDCSocketConnectionAutoRun.write(b);
            } catch (Exception e){
                log.error("下发充电任务失败{}{}",e,e.getMessage());
            }

            temp.setValue("1");
            temp.setPara2(String.valueOf(carno));
            dictService.updateDetail(temp);

        }else{
            log.error("目前暂无可使用充电桩充电桩，暂不分配{}充电任务",carno);
        }
    }

    @Override
    public boolean createChargingTaskToNDC(String carno) {
        byte carhigh = (byte) IntToHexHigh(Integer.parseInt(carno));
        byte carlow = (byte) IntToHexLow(Integer.parseInt(carno));

        String instcode = CodeUtil.getNewCode("INSTRUCT_NO");
        byte instcodehigh = (byte) IntToHexHigh(Integer.parseInt(instcode));
        byte instcodelow = (byte) IntToHexLow(Integer.parseInt(instcode));

        String str = "十进制下发：";
        String str1 = "十六进制下发：";
        str += "carno:" + (Integer.parseInt(carno));
        str1 += "carno:" + hexToString(carhigh & 0xFF) + hexToString(carlow & 0xFF);

        str += "/instcode:" + (instcode);
        str1 += "/instcode:" + hexToString(instcodehigh & 0xFF) + hexToString(instcodelow & 0xFF);

        System.out.println(str);
        System.out.println(str1);

        byte[] b = new byte[]{(byte) 0X87, (byte) 0XCD,
                (byte) 0X00, (byte) 0X08,
                (byte) 0X00, (byte) 0X0C,
                (byte) 0X00, (byte) 0X01,
                (byte) 0X00, (byte) 0X71,
                (byte) 0X00, (byte) 0X08,
                (byte) 0X64, (byte) 0X80,
                (byte) 0X00, (byte) 0X01,
                (byte) instcodehigh, (byte) instcodelow,
                (byte) carhigh, (byte) carlow
        };
        log.info("下发AGV充电任务--{}", str1);

        try{
            OneNDCSocketConnectionAutoRun.write(b);
        } catch (Exception e){
            e.getMessage();
            return false;
        }
        System.out.println("下发agv充电任务数据:" + Bytes2HexString(b));
        return true;
    }

    String hexToString(int i) {
        return (i < 16 ? "0" + Integer.toHexString(i) : Integer.toHexString(i)).toUpperCase();
    }


    public static int IntToHexHigh(int b) {
        int big = (b & 0xFF00) >> 8;
        return big;
    }

    public static int IntToHexLow(int b) {
        int little = b & 0xFF;
        return little;
    }


    public static String Bytes2HexString(byte[] b) {
        String ret = "";
        for (int i = 0; i < b.length; i++) {
            String hex = Integer.toHexString(b[i] & 0xFF);
            if (hex.length() == 1) {
                hex = '0' + hex;
            }
            ret += hex.toUpperCase();
        }
        return ret;
    }


    @LokiLog(type = LokiLogType.AGV)
    @Override
    public Map<String, AgvDto> findAllAgvFromCache() {
        return AGVDeviceStatus;
    }

}
