package com.njzscloud.common.localizer.jt808;

import com.njzscloud.common.core.utils.BCD;
import com.njzscloud.common.localizer.contant.BodyCharset;
import com.njzscloud.common.localizer.contant.MessageType;
import com.njzscloud.common.localizer.jt808.message.*;
import com.njzscloud.common.localizer.jt808.support.TcpServer;
import com.njzscloud.common.localizer.jt808.util.FlowId;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFutureListener;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * JT808消息发送工具类
 * 提供便捷的方法发送各种类型的JT808消息
 */
@Slf4j
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public final class JT808 {

    // 终端设备号与Channel的映射
    public static final Map<String, Channel> DeviceHandle = new ConcurrentHashMap<>();

    private static TcpServer tcpServer;

    public static void run(int port, int bossThreads, int workerThreads) {
        tcpServer = new TcpServer(port, bossThreads, workerThreads);
        tcpServer.start();
    }

    public static void stop() {
        if (tcpServer != null) {
            tcpServer.stop();
            tcpServer = null;
        }
    }

    /**
     * 注册终端与通道的映射关系
     */
    public static void register(String terminalId, Channel channel) {
        if (terminalId != null && channel != null) {
            if (DeviceHandle.get(terminalId) != channel) {
                DeviceHandle.put(terminalId, channel);
            }
        }
    }

    /**
     * 移除终端与通道的映射关系
     */
    public static void unregister(Channel channel) {
        if (channel != null) {
            DeviceHandle.values().removeIf(ch -> ch == channel);
        }
    }

    public static boolean isOnline(String terminalId) {
        Channel channel = DeviceHandle.get(terminalId);
        return channel != null && channel.isActive();
    }


    /**
     * 发送通用应答消息 (0x8001)
     */
    public static void sendGeneralReply(String terminalId, int messageId, int flowId, int result) {
        ServerGeneralReplyMessage replyMessage = new ServerGeneralReplyMessage(messageId, flowId, result);
        sendMessage(terminalId, MessageType.ServerGeneralReply, replyMessage);
    }

    public static void sendGeneralReply(String terminalId, int messageId, int flowId) {
        sendGeneralReply(terminalId, messageId, flowId, 0);
    }

    /**
     * 发送文本消息 (0x8300)
     */
    public static void sendTxtMessage(String terminalId, String txt, BodyCharset charset) {
        ServerTxtMessage txtMessage = new ServerTxtMessage(txt, charset);
        sendMessage(terminalId, MessageType.ServerTxtMsg, txtMessage);
    }

    public static void sendTxtMessage(String terminalId, String txt) {
        sendTxtMessage(terminalId, txt, BodyCharset.GBK);
    }

    /**
     * 向指定终端发送消息
     */
    public static void sendMessage(String terminalId, MessageType messageType, ServerMessageBody body) {
        JT808Message message = JT808.createBaseMessage(terminalId, messageType.getMessageId(), body.toBytes());
        sendMessage(message);
    }

    public static void sendMessage(JT808Message message) {
        String terminalPhone = message.getTerminalPhone();

        Channel channel = DeviceHandle.get(terminalPhone);
        if (channel != null && channel.isActive()) {
            channel.writeAndFlush(message)
                    .addListener((ChannelFutureListener) future -> {
                        if (!future.isSuccess()) {
                            log.error("消息发送失败, 终端: {}, 消息ID: 0x{}, 流水号: {}", terminalPhone, Integer.toHexString(message.getMessageId()), message.getFlowId(), future.cause());
                        }
                    });
        } else {
            unregister(channel);
            // 终端不在线或通道已关闭
            log.warn("终端不在线: {}", terminalPhone);
        }
    }

    /**
     * 创建基础消息对象
     */
    public static JT808Message createBaseMessage(String terminalId, int messageId) {
        return createBaseMessage(terminalId, messageId, null);
    }

    public static JT808Message createBaseMessage(String terminalId, int messageId, byte[] body) {
        JT808Message message = new JT808Message()
                .setFlowId(FlowId.next(terminalId, messageId));

        // 设置消息ID
        message.setMessageId(messageId);

        if (body != null) {
            message.setMessageBodyProps(body.length);
        } else {
            message.setMessageBodyProps(0);
        }

        // 设置终端手机号
        message.setTerminalPhone(terminalId);

        // 设置消息体
        message.setMessageBody(body);

        return message;
    }


    public static JT808Message parseMessage(ByteBuf buf) {
        JT808Message jt808Message = new JT808Message();

        byte[] h_b = ByteBufUtil.getBytes(buf);

        try {
            // 1. 消息ID (2字节)
            jt808Message.setMessageId(buf.readUnsignedShort());

            // 2. 消息体属性 (2字节)
            int messageBodyProps = buf.readUnsignedShort();
            jt808Message.setMessageBodyProps(messageBodyProps);

            // 3. 终端手机号 (6字节, BCD编码)
            byte[] phoneBytes = new byte[6];
            buf.readBytes(phoneBytes);
            String terminalPhone = BCD.bcdToStr(phoneBytes);
            jt808Message.setTerminalPhone(terminalPhone);

            // 4. 消息流水号 (2字节)
            jt808Message.setFlowId(buf.readUnsignedShort());

            // 5. 消息包封装项 (可选)
            if (jt808Message.isPackaged()) {
                JT808Message.PackageInfo packageInfo = new JT808Message.PackageInfo();
                packageInfo.setTotalPackages(buf.readUnsignedShort());
                packageInfo.setCurrentPackageNo(buf.readUnsignedShort());
                jt808Message.setPackageInfo(packageInfo);
            }

            // 6. 消息体
            int bodyLength = jt808Message.getMessageBodyLength();
            if (buf.readableBytes() >= bodyLength + 1) { // 消息体 + 校验码
                ByteBuf bodyBuf = buf.readSlice(bodyLength);
                byte[] array = ByteBufUtil.getBytes(bodyBuf);
                jt808Message.setMessageBody(array);

                // 7. 校验码 (1字节)
                byte checkCode = buf.readByte();
                jt808Message.setCheckCode(checkCode);


                if (jt808Message.getMessageId() == 0x704) {
                    log.info("报文：{}", h_b);
                }

                int code = 0;
                for (int i = 0; i < h_b.length - 1; i++) {
                    code = code ^ h_b[i];
                }
                if (code != checkCode) {
                    log.error("校验码错误: {}  {}", code, checkCode);
                    // return null;
                }
                return jt808Message;
            }
        } catch (Exception e) {
            log.error("消息解析错误", e);
            jt808Message = null;
        }
        return jt808Message;
    }

    private static boolean verifyCheckCode(JT808Message message, ByteBuf originalBuf) {
        return true;
    }

    public static void sendServerRegisterReply(String terminalId, int flowId, int result, String authCode) {
        ServerRegisterReplyMessage serverRegisterReplyMessage = new ServerRegisterReplyMessage(terminalId, flowId, result, authCode);
        JT808.sendMessage(JT808.createBaseMessage(terminalId, MessageType.ServerRegisterReply.getMessageId(), serverRegisterReplyMessage.toBytes()));
    }

    public static void sendServerRegisterReply(String terminalId, int flowId, String authCode) {
        sendServerRegisterReply(terminalId, flowId, 0, authCode);
    }
}
