//
// This file is a part of UERANSIM project.
// Copyright (c) 2023 ALİ GÜNGÖR.
//
// https://github.com/aligungr/UERANSIM/
// See README, LICENSE, and CONTRIBUTING files for licensing details.
//

#pragma once

#include <cstddef>
#include <cstdint>
#include <memory>
#include <utility>
#include <vector>

#include <utils/octet_string.hpp>

namespace nas
{

enum class EProtocolConfigId
{
    PROTOCOL_ID_LCP = 0xC021,
    PROTOCOL_ID_PAP = 0xC023,
    PROTOCOL_ID_CHAP = 0xC223,
    PROTOCOL_ID_IPCP = 0x8021,

    CONT_ID_UP_PCSCF_IPV6_ADDRESS_REQUEST = 0x0001,
    CONT_ID_UP_IM_CN_SUBSYSTEM_SIGNALING_FLAG = 0x0002,
    CONT_ID_UP_DNS_SERVER_IPV6_ADDRESS_REQUEST = 0x0003,
    CONT_ID_UP_MS_SUPPORT_OF_NETWORK_REQUESTED_BEARER_CONTROL_INDICATOR = 0x0005,
    CONT_ID_UP_DSMIPV6_HOME_AGENT_ADDRESS_REQUEST = 0x0007,
    CONT_ID_UP_DSMIPV6_HOME_NETWORK_PREFIX_REQUEST = 0x0008,
    CONT_ID_UP_DSMIPV6_IPV4_HOME_AGENT_ADDRESS_REQUEST = 0x0009,
    CONT_ID_UP_IP_ADDRESS_ALLOCATION_VIA_NAS_SIGNALLING = 0x000A,
    CONT_ID_UP_IPV4_ADDRESS_ALLOCATION_VIA_DHCPV4 = 0x000B,
    CONT_ID_UP_P_CSCF_IPV4_ADDRESS_REQUEST = 0x000C,
    CONT_ID_UP_DNS_SERVER_IPV4_ADDRESS_REQUEST = 0x000D,
    CONT_ID_UP_MSISDN_REQUEST = 0x000E,
    CONT_ID_UP_IFOM_SUPPORT_REQUEST = 0x000F,
    CONT_ID_UP_IPV4_LINK_MTU_REQUEST = 0x0010,
    CONT_ID_UP_MS_SUPPORT_OF_LOCAL_ADDRESS_IN_TFT_INDICATOR = 0x0011,
    CONT_ID_UP_P_CSCF_RE_SELECTION_SUPPORT = 0x0012,
    CONT_ID_UP_NBIFOM_REQUEST_INDICATOR = 0x0013,
    CONT_ID_UP_NBIFOM_MODE = 0x0014,
    CONT_ID_UP_NON_IP_LINK_MTU_REQUEST = 0x0015,
    CONT_ID_UP_APN_RATE_CONTROL_SUPPORT_INDICATOR = 0x0016,
    CONT_ID_UP_3GPP_PS_DATA_OFF_UE_STATUS = 0x0017,
    CONT_ID_UP_RELIABLE_DATA_SERVICE_REQUEST_INDICATOR = 0x0018,
    CONT_ID_UP_ADDITIONAL_APN_RATE_CONTROL_FOR_EXCEPTION_DATA_SUPPORT_INDICATOR = 0x0019,
    CONT_ID_UP_PDU_SESSION_ID = 0x001A,
    CONT_ID_UP_ETHERNET_FRAME_PAYLOAD_MTU_REQUEST = 0x0020,
    CONT_ID_UP_UNSTRUCTURED_LINK_MTU_REQUEST = 0x0021,
    CONT_ID_UP_5GSM_CAUSE_VALUE = 0x0022,
    CONT_ID_UP_QOS_RULES_WITH_THE_LENGTH_OF_TWO_OCTETS_SUPPORT_INDICATOR = 0x0023,
    CONT_ID_UP_QOS_FLOW_DESCRIPTIONS_WITH_THE_LENGTH_OF_TWO_OCTETS_SUPPORT_INDICATOR = 0x0024,
    CONT_ID_UP_ACS_INFORMATION_REQUEST = 0x0027,
    CONT_ID_UP_ATSSS_REQUEST = 0x0030,
    CONT_ID_UP_DNS_SERVER_SECURITY_INFORMATION_INDICATOR = 0x0031,

    CONT_ID_DOWN_P_CSCF_IPV6_ADDRESS = 0x0001,
    CONT_ID_DOWN_IM_CN_SUBSYSTEM_SIGNALING_FLAG = 0x0002,
    CONT_ID_DOWN_DNS_SERVER_IPV6_ADDRESS = 0x0003,
    CONT_ID_DOWN_POLICY_CONTROL_REJECTION_CODE = 0x0004,
    CONT_ID_DOWN_SELECTED_BEARER_CONTROL_MODE = 0x0005,
    CONT_ID_DOWN_DSMIPV6_HOME_AGENT_ADDRESS = 0x0007,
    CONT_ID_DOWN_DSMIPV6_HOME_NETWORK_PREFIX = 0x0008,
    CONT_ID_DOWN_DSMIPV6_IPV4_HOME_AGENT_ADDRESS = 0x0009,
    CONT_ID_DOWN_P_CSCF_IPV4_ADDRESS = 0x000C,
    CONT_ID_DOWN_DNS_SERVER_IPV4_ADDRESS = 0x000D,
    CONT_ID_DOWN_MSISDN = 0x000E,
    CONT_ID_DOWN_IFOM_SUPPORT = 0x000F,
    CONT_ID_DOWN_IPV4_LINK_MTU = 0x0010,
    CONT_ID_DOWN_NETWORK_SUPPORT_OF_LOCAL_ADDRESS_IN_TFT_INDICATOR = 0x0011,
    CONT_ID_DOWN_NBIFOM_ACCEPTED_INDICATOR = 0x0013,
    CONT_ID_DOWN_NBIFOM_MODE = 0x0014,
    CONT_ID_DOWN_NON_IP_LINK_MTU = 0x0015,
    CONT_ID_DOWN_APN_RATE_CONTROL_PARAMETERS = 0x0016,
    CONT_ID_DOWN_3GPP_PS_DATA_OFF_SUPPORT_INDICATION = 0x0017,
    CONT_ID_DOWN_RELIABLE_DATA_SERVICE_ACCEPTED_INDICATOR = 0x0018,
    CONT_ID_DOWN_ADDITIONAL_APN_RATE_CONTROL_FOR_EXCEPTION_DATA_PARAMETERS = 0x0019,
    CONT_ID_DOWN_S_NSSAI = 0x001B,
    CONT_ID_DOWN_QOS_RULES = 0x001C,
    CONT_ID_DOWN_SESSION_AMBR = 0x001D,
    CONT_ID_DOWN_PDU_SESSION_ADDRESS_LIFETIME = 0x001E,
    CONT_ID_DOWN_QOS_FLOW_DESCRIPTIONS = 0x001F,
    CONT_ID_DOWN_ETHERNET_FRAME_PAYLOAD_MTU = 0x0020,
    CONT_ID_DOWN_UNSTRUCTURED_LINK_MTU = 0x0021,
    CONT_ID_DOWN_QOS_RULES_WITH_THE_LENGTH_OF_TWO_OCTET = 0x0023,
    CONT_ID_DOWN_QOS_FLOW_DESCRIPTIONS_WITH_THE_LENGTH_OF_TWO_OCTETS = 0x0024,
    CONT_ID_DOWN_SMALL_DATA_RATE_CONTROL_PARAMETERS = 0x0025,
    CONT_ID_DOWN_ADDITIONAL_SMALL_DATA_RATE_CONTROL_FOR_EXCEPTION_DATA_PARAMETERS = 0x0026,
    CONT_ID_DOWN_ACS_INFORMATION = 0x0027,
    CONT_ID_DOWN_INITIAL_SMALL_DATA_RATE_CONTROL_PARAMETERS = 0x0028,
    CONT_ID_DOWN_INITIAL_ADDITIONAL_SMALL_DATA_RATE_CONTROL_FOR_EXCEPTION_DATA_PARAMETERS = 0x0029,
    CONT_ID_DOWN_INITIAL_APN_RATE_CONTROL_PARAMETERS = 0x002A,
    CONT_ID_DOWN_INITIAL_ADDITIONAL_APN_RATE_CONTROL_FOR_EXCEPTION_DATA_PARAMETERS = 0x002B,
    CONT_ID_DOWN_ATSSS_RESPONSE_WITH_THE_LENGTH_OF_TWO_OCTETS = 0x0030,
    CONT_ID_DOWN_DNS_SERVER_SECURITY_INFORMATION_WITH_LENGTH_OF_TWO_OCTETS = 0x0031,
};

struct ProtocolConfigurationItem
{
    const EProtocolConfigId id;
    const bool isUplink;
    const OctetString content;

    ProtocolConfigurationItem(EProtocolConfigId id, bool isUplink, OctetString content)
        : id(id), isUplink(isUplink), content(std::move(content))
    {
    }
};

class ProtocolConfigurationOptions
{
  public:
    std::vector<std::unique_ptr<ProtocolConfigurationItem>> configurationProtocols{};
    std::vector<std::unique_ptr<ProtocolConfigurationItem>> additionalParams{};

  private:
    static inline bool IsProtocolId(int id);
    static inline bool IsTwoOctetLengthContainerId(int id, bool isUplink);

  public:
    static std::unique_ptr<ProtocolConfigurationOptions> Decode(uint8_t *data, size_t len, bool isUplink);

    OctetString encode();
};

} // namespace nas