package com.njzscloud.common.localizer.jt808.support;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.map.MapUtil;
import com.njzscloud.common.localizer.DeviceStore;
import com.njzscloud.common.localizer.Localizer;
import com.njzscloud.common.localizer.contant.LocalizerType;
import com.njzscloud.common.localizer.contant.MessageType;
import com.njzscloud.common.localizer.jt808.JT808;
import com.njzscloud.common.localizer.jt808.message.*;
import com.njzscloud.common.localizer.mqtt.result.RealtimeLocationResult;
import com.njzscloud.common.mqtt.util.Mqtt;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import lombok.extern.slf4j.Slf4j;

import java.util.function.Consumer;

@Slf4j
public abstract class JT808MessageListener {

    public JT808MessageListener(LocalizerType localizerType) {
        JT808MessageCenter.addListeners(localizerType, MapUtil.<MessageType, Consumer<TerminalMessageBody>>builder()
                .put(MessageType.TerminalRegister, this::onTerminalRegister)
                .put(MessageType.TerminalAuth, this::onTerminalAuth)
                .put(MessageType.TerminalGeneralReply, this::onGeneralReport)
                .put(MessageType.TerminalHeartbeat, this::onHeartbeat)
                .put(MessageType.TerminalLocationReport, this::onLocationReport)
                .put(MessageType.TerminalLocationBatchReport, this::onLocationBatchUpload)
                .put(MessageType.TerminalLocationSearchReply, this::onLocationSearchReport)
                .put(MessageType.TerminalTxtMsg, this::onTxtReport)
                .build());
    }

    /**
     * 终端注册消息
     */
    public void onTerminalRegister(TerminalMessageBody message) {
        String terminalId = message.getTerminalId();
        int flowId = message.getFlowId();
        JT808.sendServerRegisterReply(terminalId, flowId, terminalId);
        byte[] body = message.getBody();
        ByteBuf byteBuf = Unpooled.wrappedBuffer(body);

        TerminalRegisterMessage terminalRegisterMessage = new TerminalRegisterMessage(byteBuf);

        log.info("{}，终端注册消息: {}", terminalId, terminalRegisterMessage);
    }

    /**
     * 终端鉴权消息
     */
    public void onTerminalAuth(TerminalMessageBody message) {
        String terminalId = message.getTerminalId();
        int messageId = message.getMessageId();
        int flowId = message.getFlowId();
        JT808.sendGeneralReply(terminalId, messageId, flowId);
        ByteBuf body = Unpooled.wrappedBuffer(message.getBody());
        TerminalAuthMessage authMsg = null;
        try {
            authMsg = new TerminalAuthMessage(body);
        } catch (Exception e) {
            body.release();
        }
        log.info("{}，终端鉴权消息: {}", terminalId, authMsg);
    }

    /**
     * 终端通用应答消息
     */
    public void onGeneralReport(TerminalMessageBody message) {
        ByteBuf body = Unpooled.wrappedBuffer(message.getBody());
        TerminalGeneralResponseMessage terminalGeneralResponseMessage = new TerminalGeneralResponseMessage(body);
        log.info("设备通用响应，设备号：{}，消息：{}", message.getTerminalId(), terminalGeneralResponseMessage.getResult());
    }

    /**
     * 终端心跳消息
     */
    public void onHeartbeat(TerminalMessageBody message) {
        JT808.sendGeneralReply(message.getTerminalId(), message.getMessageId(), message.getFlowId());
        String terminalId = message.getTerminalId();
        Mqtt.publish(terminalId + "/online", MapUtil.builder()
                .put("online", true)
                .put("terminalId", terminalId)
                .put("time", DateUtil.now())
                .build());
    }

    /**
     * 终端位置信息汇报消息
     */
    public void onLocationReport(TerminalMessageBody message) {
        String terminalId = message.getTerminalId();
        // JT808.sendGeneralReply(terminalId, message.getMessageId(), message.getFlowId());
        byte[] body = message.getBody();
        ByteBuf byteBuf = Unpooled.wrappedBuffer(body);
        try {
            Localizer localizer = DeviceStore.determineLocalizer(terminalId);
            if (localizer == null) {
                log.warn("未找到定位器：{}", terminalId);
                return;
            }
            LocationReportMessage locationReportMsg = new LocationReportMessage(byteBuf);
            double speed = locationReportMsg.getSpeed();
            int speedThreshold = localizer.getSpeedThreshold();
            RealtimeLocationResult realtimeLocationResult = BeanUtil.copyProperties(locationReportMsg, RealtimeLocationResult.class)
                    .setTerminalId(terminalId)
                    .setOverspeed(speed > speedThreshold);
            Mqtt.publish(terminalId + "/track_location", realtimeLocationResult);
            Mqtt.publish(terminalId + "/track_location_real", realtimeLocationResult);
        } finally {
            byteBuf.release();
        }
    }

    /**
     * 定位数据批量上传消息
     */
    public void onLocationBatchUpload(TerminalMessageBody message) {
        // JT808.sendGeneralReply(message.getTerminalId(), message.getMessageId(), message.getFlowId());
        String terminalId = message.getTerminalId();
        byte[] body = message.getBody();
        ByteBuf byteBuf = Unpooled.wrappedBuffer(body);
        try {
            int count = byteBuf.readUnsignedShort();
            int type = byteBuf.readByte();
            Localizer localizer = DeviceStore.determineLocalizer(terminalId);
            if (localizer == null) {
                log.warn("未找到定位器：{}", terminalId);
                return;
            }
            int speedThreshold = localizer.getSpeedThreshold();
            for (int i = 0; i < count; i++) {
                int length = byteBuf.readUnsignedShort();
                /* if (length > 28) { // 有扩展信息

                } */
                LocationReportMessage locationReportMsg = new LocationReportMessage(byteBuf.slice(byteBuf.readerIndex(), length));
                byteBuf.skipBytes(length);
                double speed = locationReportMsg.getSpeed();
                RealtimeLocationResult realtimeLocationResult = BeanUtil.copyProperties(locationReportMsg, RealtimeLocationResult.class)
                        .setTerminalId(terminalId)
                        .setOverspeed(speed > speedThreshold)
                        .setType(type);
                Mqtt.publish(terminalId + "/track_location", realtimeLocationResult);
                Mqtt.publish(terminalId + "/track_location_real", realtimeLocationResult);
            }
        } catch (Exception e) {
            log.error("批量上报处理失败：{} {}", terminalId, message.getFlowId());
        } finally {
            byteBuf.release();
        }
    }

    /**
     * 查询位置响应消息
     */
    public void onLocationSearchReport(TerminalMessageBody message) {
        JT808.sendGeneralReply(message.getTerminalId(), message.getMessageId(), message.getFlowId());
        String terminalId = message.getTerminalId();
        byte[] body = message.getBody();
        ByteBuf byteBuf = Unpooled.wrappedBuffer(body);
        try {
            SearchLocationResponseMessage searchLocationResponseMsg = new SearchLocationResponseMessage(byteBuf);
            LocationReportMessage locationReportMsg = searchLocationResponseMsg.getLocationReportMessage();
            RealtimeLocationResult realtimeLocationResult = BeanUtil.copyProperties(locationReportMsg, RealtimeLocationResult.class)
                    .setTerminalId(terminalId);
            Mqtt.publish(terminalId + "/current_location", realtimeLocationResult);
        } finally {
            byteBuf.release();
        }
    }

    /**
     * 终端文本信息汇报消息
     */
    public abstract void onTxtReport(TerminalMessageBody message);
}
