#ifndef FILE_AUSF_PROFILE_HPP_SEEN
#define FILE_AUSF_PROFILE_HPP_SEEN

#include <arpa/inet.h>
#include <netinet/in.h>
#include <map>
#include <memory>
#include <nlohmann/json.hpp>
#include <shared_mutex>
#include <utility>
#include <vector>

#include "logger.hpp"
#include "3gpp_29.510.h"

namespace ausf_application{

    using namespace std;
    class nf_profile : public std::enable_shared_from_this<nf_profile>
    {
    public:
        nf_profile()
            : nf_type("NF_TYPE_UNKNOWN"),
              heartBeat_timer(0),
              ipv4_addresses(),
              priority(0),
              capacity(0){
            nf_instance_name = "";
            nf_status = "";
        }

        nf_profile(const std::string &id)
            : nf_instance_id(id),
              heartBeat_timer(0),
              ipv4_addresses(),
              priority(0),
              capacity(0),
              nf_type("NF_TYPE_UNKNOWN")
        {
            nf_instance_name = "";
            nf_status = "";
        }

        nf_profile &operator=(const nf_profile &s)
        {
            nf_instance_id = s.nf_instance_id;
            heartBeat_timer = s.heartBeat_timer;
            ipv4_addresses = s.ipv4_addresses;
            priority = s.priority;
            capacity = s.capacity;
            nf_type = s.nf_type;
            nf_instance_name = s.nf_instance_name;
            nf_status = s.nf_status;
        }
        // nf_profile(nf_profile &b) = delete;
        void set_nf_instance_id(const std::string &instance_id);
        void get_nf_instance_id(std::string &instance_id) const;
        std::string get_nf_instance_id() const;
        void set_nf_instance_name(const std::string &instance_name);
        void get_nf_instance_name(std::string &instance_name) const;
        std::string get_nf_instance_name() const;
        void set_nf_status(const std::string &status);
        void get_nf_status(std::string &status) const;
        std::string get_nf_status() const;
        std::string get_nf_type() const;
        void set_nf_type(const std::string &type);
        void set_nf_heartBeat_timer(const int32_t &timer);
        void get_nf_heartBeat_timer(int32_t &timer) const;
        int32_t get_nf_heartBeat_timer() const;
        void set_nf_priority(const uint16_t &p);
        void get_nf_priority(uint16_t &p) const;
        uint16_t get_nf_priority() const;
        void set_nf_capacity(const uint16_t &c);
        void get_nf_capacity(uint16_t &c) const;
        uint16_t get_nf_capacity() const;
        void set_nf_ipv4_addresses(const std::vector<struct in_addr> &a);
        void add_nf_ipv4_addresses(const struct in_addr &a);
        void get_nf_ipv4_addresses(std::vector<struct in_addr> &a) const;
        virtual void display() const;
        virtual void to_json(nlohmann::json &data) const;
        virtual void from_json(const nlohmann::json &data);

    protected:
        // From NFProfile (Section 6.1.6.2.2@3GPP TS 29.510 V16.0.0 (2019-06))
        std::string nf_instance_id;
        std::string nf_instance_name;
        std::string nf_type;
        std::string nf_status;
        int32_t heartBeat_timer;
        std::vector<struct in_addr> ipv4_addresses;
        uint16_t priority;
        uint16_t capacity;
    };
    class ausf_profile : public nf_profile {
      public:
        ausf_profile() : nf_profile() { }

        ausf_profile(const std::string& id) : nf_profile(id) { }

        ausf_profile& operator=(const ausf_profile& s) {
            nf_instance_id   = s.nf_instance_id;
            heartBeat_timer  = s.heartBeat_timer;
            ipv4_addresses   = s.ipv4_addresses;
            priority         = s.priority;
            capacity         = s.capacity;
            nf_type          = s.nf_type;
            nf_instance_name = s.nf_instance_name;
            nf_status        = s.nf_status;
            nf_services      = s.nf_services;
            return *this;
        }

        virtual ~ausf_profile() {
            Logger::ausf_app().debug("Delete AUSF Profile instance...");
        }
        void set_nf_services(const std::vector<nf_service_t>& n);
        void add_nf_service(const nf_service_t& n);
        void get_nf_services(std::vector<nf_service_t>& n) const;
        void display() const;
        void to_json(nlohmann::json& data) const;
        void from_json(const nlohmann::json& data);
        void handle_heartbeart_timeout(uint64_t ms);
    protected:
        std::vector<nf_service_t> nf_services;
        //nlohmann::json custom_info;  // store extra json data
    };
}
#endif
