package com.alterdekim.game.component.rtmp;

import lombok.*;
import lombok.extern.slf4j.Slf4j;

import java.io.InputStream;

@ToString
@Getter
@Setter
@NoArgsConstructor
public class RTMPHeader {
    private ChunkType chunkType;
    private byte chunkStreamId;
    private int absoluteTimestamp;
    private int timestampDelta = -1;
    private int packetLength;
    private MessageType messageType;
    private int messageStreamId;

    @Getter
    @RequiredArgsConstructor
    public enum ChunkType {

        /**
         * Full 12-byte RTMP chunk header
         */
        TYPE_0_FULL((byte) 0x00, 12),
        /**
         * Relative 8-byte RTMP chunk header (message stream ID is not included)
         */
        TYPE_1_RELATIVE_LARGE((byte) 0x01, 8),
        /**
         * Relative 4-byte RTMP chunk header (only timestamp delta)
         */
        TYPE_2_RELATIVE_TIMESTAMP_ONLY((byte) 0x02, 4),
        /**
         * Relative 1-byte RTMP chunk header (no "real" header, just the 1-byte indicating chunk header type & chunk stream ID)
         */
        TYPE_3_RELATIVE_SINGLE_BYTE((byte) 0x03, 1);
        /**
         * The byte value of this chunk header type
         */
        private final byte value;
        /**
         * The full size (in bytes) of this RTMP header (including the basic header byte)
         */
        private final int size;

        public static ChunkType fromByte(byte b) {
            for( ChunkType c : values() ) {
                if( c.value == b ) return c;
            }
            return TYPE_3_RELATIVE_SINGLE_BYTE;
        }
    }

    @Slf4j
    @Getter
    @RequiredArgsConstructor
    public enum MessageType {

        /**
         * Protocol control message 1
         * Set Chunk Size, is used to notify the peer a new maximum chunk size to use.
         */
        SET_CHUNK_SIZE((byte) 0x01),
        /**
         * Protocol control message 2
         * Abort Message, is used to notify the peer if it is waiting for chunks
         * to complete a message, then to discard the partially received message
         * over a chunk stream and abort processing of that message.
         */
        ABORT((byte) 0x02),
        /**
         * Protocol control message 3
         * The client or the server sends the acknowledgment to the peer after
         * receiving bytes equal to the window size. The window size is the
         * maximum number of bytes that the sender sends without receiving
         * acknowledgment from the receiver.
         */
        ACKNOWLEDGEMENT((byte) 0x03),
        /**
         * Protocol control message 4
         * The client or the server sends this message to notify the peer about
         * the user control events. This message carries Event type and Event
         * data.
         * Also known as a PING message in some RTMP implementations.
         */
        USER_CONTROL_MESSAGE((byte) 0x04),
        /**
         * Protocol control message 5
         * The client or the server sends this message to inform the peer which
         * window size to use when sending acknowledgment.
         * Also known as ServerBW ("server bandwidth") in some RTMP implementations.
         */
        WINDOW_ACKNOWLEDGEMENT_SIZE((byte) 0x05),
        /**
         * Protocol control message 6
         * The client or the server sends this message to update the output
         * bandwidth of the peer. The output bandwidth value is the same as the
         * window size for the peer.
         * Also known as ClientBW ("client bandwidth") in some RTMP implementations.
         */
        SET_PEER_BANDWIDTH((byte) 0x06),
        /**
         * RTMP audio packet (0x08)
         * The client or the server sends this message to send audio data to the peer.
         */
        AUDIO((byte) 0x08),
        /**
         * RTMP video packet (0x09)
         * The client or the server sends this message to send video data to the peer.
         */
        VIDEO((byte) 0x09),
        /**
         * RTMP message type 0x0F
         * The client or the server sends this message to send Metadata or any
         * user data to the peer. Metadata includes details about the data (audio, video etc.)
         * like creation time, duration, theme and so on.
         * This is the AMF3-encoded version.
         */
        DATA_AMF3((byte) 0x0F),
        /**
         * RTMP message type 0x10
         * A shared object is a Flash object (a collection of name value pairs)
         * that are in synchronization across multiple clients, instances, and
         * so on.
         * This is the AMF3 version: kMsgContainerEx=16 for AMF3.
         */
        SHARED_OBJECT_AMF3((byte) 0x10),
        /**
         * RTMP message type 0x11
         * Command messages carry the AMF-encoded commands between the client
         * and the server.
         * A command message consists of command name, transaction ID, and command object that
         * contains related parameters.
         * This is the AMF3-encoded version.
         */
        COMMAND_AMF3((byte) 0x11),
        /**
         * RTMP message type 0x12
         * The client or the server sends this message to send Metadata or any
         * user data to the peer. Metadata includes details about the data (audio, video etc.)
         * like creation time, duration, theme and so on.
         * This is the AMF0-encoded version.
         */
        DATA_AMF0((byte) 0x12),
        /**
         * RTMP message type 0x14
         * Command messages carry the AMF-encoded commands between the client
         * and the server.
         * A command message consists of command name, transaction ID, and command object that
         * contains related parameters.
         * This is the common AMF0 version, also known as INVOKE in some RTMP implementations.
         */
        COMMAND_AMF0((byte) 0x14),
        /**
         * RTMP message type 0x13
         * A shared object is a Flash object (a collection of name value pairs)
         * that are in synchronization across multiple clients, instances, and
         * so on.
         * This is the AMF0 version: kMsgContainer=19 for AMF0.
         */
        SHARED_OBJECT_AMF0((byte) 0x13),
        /**
         * RTMP message type 0x16
         * An aggregate message is a single message that contains a list of sub-messages.
         */
        AGGREGATE_MESSAGE((byte) 0x16);

        private final byte value;

        public static MessageType valueOf(byte b) {
            for( MessageType c : values() ) {
                if( c.value == b ) return c;
            }
            log.warn("gosh im tired: {}", b);
            return MessageType.ABORT;
        }
    }
}
