package com.lutao.cloud.iot.mqtt.core.client;

import com.lutao.cloud.iot.mqtt.codec.*;
import org.tio.client.intf.ClientAioHandler;
import org.tio.core.ChannelContext;
import org.tio.core.TioConfig;
import org.tio.core.exception.TioDecodeException;
import org.tio.core.intf.Packet;

import java.nio.ByteBuffer;

/**
 * mqtt 客户端处理
 */
public class MqttClientAioHandler implements ClientAioHandler {
    private final MqttDecoder mqttDecoder;
    private final MqttEncoder mqttEncoder;
    private final ByteBufferAllocator allocator;
    private final IMqttClientProcessor processor;

    public MqttClientAioHandler(MqttClientCreator mqttClientCreator,
                                IMqttClientProcessor processor) {
        this.mqttDecoder = new MqttDecoder(mqttClientCreator.getMaxBytesInMessage(), mqttClientCreator.getMaxClientIdLength());
        this.mqttEncoder = MqttEncoder.INSTANCE;
        this.allocator = mqttClientCreator.getBufferAllocator();
        this.processor = processor;
    }

    @Override
    public Packet heartbeatPacket(ChannelContext channelContext) {
        return MqttMessage.PINGREQ;
    }

    @Override
    public Packet decode(ByteBuffer buffer, int limit, int position, int readableLength, ChannelContext context) throws TioDecodeException {
        return mqttDecoder.doDecode(context, buffer, limit, position, readableLength);
    }

    @Override
    public ByteBuffer encode(Packet packet, TioConfig tioConfig, ChannelContext channelContext) {
        return mqttEncoder.doEncode(channelContext, (MqttMessage) packet, allocator);
    }

    @Override
    public void handler(Packet packet, ChannelContext context) {
        MqttMessage message = (MqttMessage) packet;
        // 1. 先判断 mqtt 消息解析是否正常
        DecoderResult decoderResult = message.decoderResult();
        if (decoderResult.isFailure()) {
            processor.processDecodeFailure(context, message, decoderResult.getCause());
            return;
        }
        MqttFixedHeader fixedHeader = message.fixedHeader();
        // 根据消息类型处理消息
        MqttMessageType messageType = fixedHeader.messageType();
        switch (messageType) {
            case CONNACK:
                processor.processConAck(context, (MqttConnAckMessage) message);
                break;
            case SUBACK:
                processor.processSubAck((MqttSubAckMessage) message);
                break;
            case PUBLISH:
                processor.processPublish(context, (MqttPublishMessage) message);
                break;
            case UNSUBACK:
                processor.processUnSubAck((MqttUnsubAckMessage) message);
                break;
            case PUBACK:
                processor.processPubAck((MqttPubAckMessage) message);
                break;
            case PUBREC:
                processor.processPubRec(context, message);
                break;
            case PUBREL:
                processor.processPubRel(context, message);
                break;
            case PUBCOMP:
                processor.processPubComp(message);
                break;
            default:
                break;
        }
    }

}
