package cn.iocoder.yudao.module.remote.api.robot;

import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.module.remote.config.ip.IpProperties;
import cn.iocoder.yudao.module.remote.controller.admin.robot.dto.Cockpit;
import cn.iocoder.yudao.module.remote.controller.admin.robot.dto.RemoteControllerSocketDTO;
import cn.iocoder.yudao.module.remote.enums.robot.RemoteIpTypeEnum;
import cn.iocoder.yudao.module.remote.util.crc.CRCUtil;
import cn.iocoder.yudao.module.system.api.remote.dto.RemoteRobotTransferDTO;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.PreDestroy;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.REMOTE_ROBOT_CONNECT_FAIL;

@Component
@Slf4j
public class RemoteControllerProcessor {
    public final ConcurrentHashMap<String, RemoteControllerSocketDTO> cache = new ConcurrentHashMap<>();

    public final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);

    public final Map<String,Socket> socketMap = new HashMap<>();

    @Value("${remote.msg}")
    private String defaultMsg;

    @Value("${remote.cockpit-time-out}")
    private int cockpitTimeOut;

    @Value("${remote.industrial-control-time-out}")
    private int industrialControlTimeOut;

    @Value("${remote.robot-communication-time-out}")
    private int robotCommunicationTimeOut;

    private final String ONE = "01";
    private final String TWO = "02";

    @Autowired
    private IpProperties ipProperties;

    public void addCache(RemoteRobotTransferDTO dto, String ip) {
        log.info("网页端IP :{}", ip);
        Cockpit cockpit = ipProperties.getCockpitByIp(ip);
        log.info("SOCKET服务端信息 :{}", JSON.toJSONString(cockpit));
        String cockpitIp = cockpit.getControllerIp();
        int cockpitPort = cockpit.getControllerPort();

        RemoteControllerSocketDTO remoteControllerSocketDTO = cache.get(cockpitIp);
        log.info("是否为空 :{}", ObjectUtil.isEmpty(remoteControllerSocketDTO));
        if (ObjectUtil.isNotEmpty(remoteControllerSocketDTO)) {
            try {
                Socket socket = remoteControllerSocketDTO.getSocket();
                if (socket != null && !socket.isClosed()) {
                    socket.close();
                }
                log.info("关闭socket :{}", cockpitIp);
            } catch (IOException e) {
                log.error("关闭socket出现异常 :{}", cockpitIp);
                throw new RuntimeException(e);
            }
        } else {
            remoteControllerSocketDTO = new RemoteControllerSocketDTO();
        }
        remoteControllerSocketDTO.setControllerIp(cockpitIp);
        remoteControllerSocketDTO.setControllerPort(cockpitPort);
        Socket socket = new Socket();
        try {
            socket.setKeepAlive(true);
            socket.connect(new InetSocketAddress(cockpitIp, cockpitPort), 500);
            remoteControllerSocketDTO.setSocket(socket);
        } catch (IOException e) {
            log.error("添加socket失败 :{}", e);
            throw exception(REMOTE_ROBOT_CONNECT_FAIL);
        }
        setMsg(remoteControllerSocketDTO, RemoteIpTypeEnum.ONE.getType(), dto);
        cache.put(cockpitIp, remoteControllerSocketDTO);
    }

    /**
     * 设置
     *
     * @param remoteControllerSocket
     * @param type
     */
    public void setMsg(RemoteControllerSocketDTO remoteControllerSocket, Integer type, RemoteRobotTransferDTO dto) {
        log.info("驾舱控制的车辆IP :{}, 端口:{}", dto.getRobotIp(), dto.getRobotPort());
        String msg = defaultMsg;
        if (RemoteIpTypeEnum.ONE.getType().equals(type)) {
            msg = msg + " " + ONE;
        } else {
            msg = msg + " " + TWO;
        }

        String[] split = dto.getRobotIp().split("\\.");
        for (String ipItem : split) {
            String hex = Integer.toHexString(Integer.valueOf(ipItem)).toUpperCase();
            if (hex.length() == 1) {
                hex = 0 + hex;
            }
            msg = msg + " " + hex;
            log.info("组装 :{}", hex);
        }

        String portHex = Integer.toHexString(dto.getRobotPort().intValue());
        String portHexOne = portHex.substring(0, 2);
        String portHexTwo = portHex.substring(2);
        msg = msg + " " + portHexTwo + " " + portHexOne;
        if (cockpitTimeOut > 0) {
            msg = msg + " " + ONE + " " + Integer.toHexString(cockpitTimeOut);
        } else {
            msg = msg + " " + TWO + " " + Integer.toHexString(cockpitTimeOut);
        }

        if (industrialControlTimeOut > 0) {
            msg = msg + " " + ONE + " " + Integer.toHexString(industrialControlTimeOut);
        } else {
            msg = msg + " " + TWO + " " + Integer.toHexString(industrialControlTimeOut);
        }

        if (robotCommunicationTimeOut > 0) {
            msg = msg + " " + ONE + " " + Integer.toHexString(robotCommunicationTimeOut);
        } else {
            msg = msg + " " + TWO + " " + Integer.toHexString(robotCommunicationTimeOut);
        }

        String crc = CRCUtil.getCRC(msg);
        String crcOne = crc.substring(0, 2);
        String crcTwo = crc.substring(2);

        msg = msg + " " + crcOne + " " + crcTwo;

        remoteControllerSocket.setMsg(hexStringToByteArray(msg));
    }

    public String hexStringToByteArray(String hexString) {
        // 移除所有空格（包括中间和两端的空格）
        String cleaned = hexString.replaceAll("\\s", "");

        // 验证字符串长度是否为偶数
        if (cleaned.length() % 2 != 0) {
            throw new IllegalArgumentException("无效的十六进制字符串长度: " + cleaned.length());
        }

        // 创建结果字节数组
        byte[] byteArray = new byte[cleaned.length() / 2];

        for (int i = 0; i < cleaned.length(); i += 2) {
            // 提取两个连续的十六进制字符
            String hexPair = cleaned.substring(i, i + 2);

            try {
                // 将十六进制字符串转换为字节
                byteArray[i / 2] = (byte) Integer.parseInt(hexPair, 16);
            } catch (NumberFormatException e) {
                throw new IllegalArgumentException("无效的十六进制字符: " + hexPair);
            }
        }

        String str = Arrays.toString(byteArray);
        return str.substring(1, str.length() - 1);
    }

    public void remoteCache(RemoteRobotTransferDTO dto, String ip) {
        Cockpit cockpit = ipProperties.getCockpitByIp(ip);
        String cockpitIp = cockpit.getControllerIp();
        RemoteControllerSocketDTO remoteControllerSocketDTO = cache.get(cockpitIp);
        if (ObjectUtil.isEmpty(remoteControllerSocketDTO)) {
            return;
        }
        setMsg(remoteControllerSocketDTO, RemoteIpTypeEnum.THREE.getType(), dto);
        cache.remove(cockpitIp);

        Socket socket = remoteControllerSocketDTO.getSocket();
        if (socket == null || socket.isClosed()) {
            try {
                socket = new Socket();
                log.info("连接新的的socket");
                socket.setKeepAlive(true);
                socket.connect(new InetSocketAddress(cockpitIp, cockpit.getControllerPort()), 1000);
            } catch (IOException e) {
                log.error("连接socket出现异常 :{}", cockpitIp);
            }
        }

        OutputStream os = null;
        try {
            os = socket.getOutputStream();
            log.info("断开连接 :{} ,对应的IP  :{}", remoteControllerSocketDTO.getMsg(), remoteControllerSocketDTO.getControllerIp());
            os.write(remoteControllerSocketDTO.getMsg().getBytes());
            socket.shutdownInput();
            socket.close();
            log.info("关闭socket :{}", cockpitIp);
        } catch (IOException e) {
            log.error("关闭socket出现异常 :{}", cockpitIp);
        } finally {
            if (ObjectUtil.isNotEmpty(os)) {
                try {
                    os.close();
                } catch (IOException e) {
                }
            }
        }

        remoteCache(dto, ip);
    }


    /*public RemoteControllerProcessor() {
        // 每秒执行一次 - 处理并发送数据 - 避免数据丢失
        scheduler.scheduleAtFixedRate(this::processAndSend, 150, 150, TimeUnit.MILLISECONDS);
    }*/

    public void processAndSend() {
        if (ObjectUtil.isEmpty(cache)) {
            return;
        }
//        log.info("socket发送数据开始");
        for (Map.Entry<String, RemoteControllerSocketDTO> v : cache.entrySet()) {
            RemoteControllerSocketDTO remoteControllerSocketDTO = v.getValue();

            Socket socket = socketMap.get("1");
            if (socket == null || socket.isClosed()) {
                socket = new Socket();
                try {
                    log.info("socket建立新连接");
                    socket.connect(new InetSocketAddress(v.getKey(), remoteControllerSocketDTO.getControllerPort()), 1000);
                    remoteControllerSocketDTO.setSocket(socket);
                } catch (IOException e) {
                    log.error("socket重连异常 :{}", e);
                }
            }

            OutputStream os = null;
            try {
                os = socket.getOutputStream();
                String str = remoteControllerSocketDTO.getMsg();
                String[] split = str.split(",");
                for (String meg : split) {
                    os.write(Integer.parseInt(meg.trim()));
                }
                log.info("socket推送的数据 :{}", str);
            } catch (IOException e) {
                log.error("socket发送异常 :{}", e);
            } finally {
                if (ObjectUtil.isNotEmpty(os)) {
                    try {
                        os.flush();
                    } catch (IOException e) {
                    }
                }
            }
        }
    }


    public void shutdown() {
        scheduler.shutdown();
    }

    @PreDestroy
    public void destroy() {
        // 在Bean销毁前关闭去啊
        shutdown();
    }

    public void putSocket(Socket socket) {
        socketMap.put("1",socket);
    }
}
