#ifndef MS_RTC_SUBCHANNELS_CODEC_HPP
#define MS_RTC_SUBCHANNELS_CODEC_HPP

#include "common.hpp"
#include "RTC/SCTP/public/Message.hpp"
#include <vector>

namespace RTC
{
	/**
	 * Helper to (optionally) encode/decode subchannels, required subchannel and
	 * ignored subchannel at the beginning of an SCTP message payload so that this
	 * information travels within the SCTP message itself.
	 */
	class SubchannelsCodec
	{
		/**
		 * Wire layout of the encoded header prepended to the message payload (all
		 * fields in network byte order). `R` is the `requiredSubchannelFlag` (second
		 * least significant bit of the Magic Token) and `I` is the
		 * `ignoredSubchannelFlag` (least significant bit of the Magic Token). The
		 * `requiredSubchannel` field is only present when `R` is 1. The
		 * `ignoredSubchannel` field is only present when `I` is 1.
		 *
		 *  0                   1                   2                   3
		 *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
		 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
		 * |                       Magic Token (1/2)                       |
		 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
		 * |                     Magic Token (2/2)                     |R|I|
		 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
		 * |        subchannelsCount       |          Subchannel 0         |
		 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
		 * |                              ...                              |
		 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
		 * |         Subchannel N-2        |          Subchannel N-1       |
		 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
		 * |  requiredSubchannel (if R=1)  |   ignoredSubchannel (if I=1)  |
		 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
		 */

	public:
		/**
		 * 8-byte Magic Token that prefixes an encoded payload. It is intentionally
		 * made of non-printable high bytes and starts with a byte that is not a valid
		 * UTF-8 leading byte (0x80-0xBF), so a real string message (valid UTF-8) can
		 * never begin with it and the chance of colliding with a binary message is
		 * negligible. Its least significant bits are reserved for the
		 * `requiredSubchannelFlag` and `ignoredSubchannelFlag`, so they are always 0
		 * in the token constant itself.
		 */
		static constexpr uint64_t MagicToken{ 0xA5F09CB3D6E1F28C };
		static constexpr uint64_t RequiredSubchannelFlagMask{ 0x2 };
		static constexpr uint64_t IgnoredSubchannelFlagMask{ 0x1 };
		static constexpr uint64_t FlagsMask{ RequiredSubchannelFlagMask | IgnoredSubchannelFlagMask };

	public:
		/**
		 * If `subchannels` is not empty or `requiredSubchannel` or `ignoredSubchannel`
		 * has value, encodes them at the beginning of the given message payload.
		 *
		 * @returns true if the message was encoded, false otherwise.
		 */
		static bool EncodeSubchannels(
		  RTC::SCTP::Message& message,
		  const std::vector<uint16_t>& subchannels,
		  std::optional<uint16_t> requiredSubchannel,
		  std::optional<uint16_t> ignoredSubchannel);

		/**
		 * If the given message payload starts with the Magic Token, extracts the
		 * encoded subchannels and (optionally) the required and/or ignored subchannel,
		 * fills the given arguments and removes the encoded header from the message
		 * payload.
		 *
		 * @returns true if the message was successfully decoded, false otherwise.
		 */
		static bool DecodeSubchannels(
		  RTC::SCTP::Message& message,
		  std::vector<uint16_t>& subchannels,
		  std::optional<uint16_t>& requiredSubchannel,
		  std::optional<uint16_t>& ignoredSubchannel);
	};
} // namespace RTC

#endif
