package com.njzscloud.common.localizer.jt808;

import com.njzscloud.common.core.utils.BCD;
import com.njzscloud.common.localizer.jt808.message.JT808Message;
import com.njzscloud.common.localizer.jt808.message.ServerGeneralResponseMessage;
import com.njzscloud.common.localizer.jt808.message.ServerTxtMessage;
import com.njzscloud.common.localizer.jt808.message.TerminalMessageBody;
import com.njzscloud.common.localizer.jt808.support.JT808MessageResolver;
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;
import java.util.function.Consumer;

/**
 * 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 addListener(String messageId, Consumer<TerminalMessageBody> listener) {
        JT808MessageResolver.addResolver(messageId, listener);
    }

    /**
     * 注册终端与通道的映射关系
     */
    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);
        }
    }

    /**
     * 发送通用应答消息 (0x8001)
     */
    public static void sendGeneralResponse(JT808Message message, int result) {
        String terminalPhone = message.getTerminalPhone();
        int flowId = message.getFlowId();
        int messageId = message.getMessageId();
        ServerGeneralResponseMessage response = new ServerGeneralResponseMessage(messageId, flowId, result);

        message = JT808.createBaseMessage(terminalPhone, 0x8001, response.toBytes());
        sendMessage(message);
    }

    public static void sendGeneralResponse(JT808Message message) {
        sendGeneralResponse(message, 0);
    }

    /**
     * 发送文本消息 (0x8300)
     */
    public static void sendTxtMessage(String terminalId, String txt) {
        ServerTxtMessage txtMessage = new ServerTxtMessage(txt);
        JT808Message message = JT808.createBaseMessage(terminalId, 0x8300, txtMessage.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.info("消息发送成功, 终端: {}, 消息ID: 0x{}, 流水号: {}", terminalPhone, Integer.toHexString(message.getMessageId()), message.getFlowId());
                        } else {
                            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();

        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字节)
                jt808Message.setCheckCode(buf.readByte());

                // 验证校验码
                if (!verifyCheckCode(jt808Message, buf)) {
                    log.error("校验码错误: {}", jt808Message);
                    return null;
                }

                return jt808Message;
            }
        } catch (Exception e) {
            log.error("消息解析错误", e);
            jt808Message = null;
        }
        return jt808Message;
    }

    private static boolean verifyCheckCode(JT808Message message, ByteBuf originalBuf) {
        // 简化实现，实际项目中需要根据协议规范计算校验码
        // 校验码 = 消息头 + 消息体 中所有字节的异或
        return true;
    }


}
