/**
 * Copyright 2024 Centreon
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * For more information : contact@centreon.com
 */

#include <ifaddrs.h>
#include <netdb.h>

#include "agent_info.hh"
#include "version.hh"

static std::string _os;
static std::string _os_version;

/**
 * @brief read os version
 * to call at the beginning of program
 *
 */
void com::centreon::agent::read_os_version() {
  std::fstream os_release("/etc/os-release", std::fstream::in);
  if (os_release.is_open()) {
    enum { os_found = 1, version_found = 2, all_found = 3 };
    unsigned found = 0;
    std::string line;
    while (std::getline(os_release, line) && found != all_found) {
      if (!line.compare(0, 3, "ID=")) {
        line.erase(0, 3);
        boost::algorithm::trim_if(line, [](const char c) {
          return c == '"' || c == ' ' || c == '\'';
        });
        _os = line;
        found |= os_found;
      } else if (!line.compare(0, 11, "VERSION_ID=")) {
        line.erase(0, 11);
        boost::algorithm::trim_if(line, [](const char c) {
          return c == '"' || c == ' ' || c == '\'';
        });
        _os_version = line;
        found |= version_found;
      }
    }
  }
}

/**
 * @brief fill agent_info with agent and os versions
 *
 * @param supervised_host host configured
 * @param agent_info pointer to object to fill
 */
void com::centreon::agent::fill_agent_info(
    const std::string& supervised_host,
    const std::string& host_template,
    ::com::centreon::agent::AgentInfo* agent_info,
    const std::shared_ptr<spdlog::logger>& logger) {
  agent_info->mutable_centreon_version()->set_major(
      CENTREON_AGENT_VERSION_MAJOR);
  agent_info->mutable_centreon_version()->set_minor(
      CENTREON_AGENT_VERSION_MINOR);
  agent_info->mutable_centreon_version()->set_patch(
      CENTREON_AGENT_VERSION_PATCH);
  agent_info->set_host(supervised_host);
  agent_info->set_host_template(host_template);
  agent_info->set_os(_os);
  agent_info->set_os_version(_os_version);
  agent_info->set_encryption_ready(true);

  struct ifaddrs* ifaddr = nullptr;
  if (getifaddrs(&ifaddr)) {
    SPDLOG_LOGGER_ERROR(logger, "fail to list interface adresses");
    return;
  }
  for (struct ifaddrs* ifa = ifaddr; ifa; ifa = ifa->ifa_next) {
    if (ifa->ifa_addr == nullptr || !(ifa->ifa_flags & IFF_UP)) {
      continue;
    }
    if (ifa->ifa_flags & IFF_LOOPBACK) {
      continue;
    }
    int family = ifa->ifa_addr->sa_family;
    if (family == AF_INET || family == AF_INET6) {
      char host[NI_MAXHOST];
      int res = getnameinfo(ifa->ifa_addr,
                            (family == AF_INET) ? sizeof(struct sockaddr_in)
                                                : sizeof(struct sockaddr_in6),
                            host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
      if (!res) {
        agent_info->add_ips(host);
      } else {
        SPDLOG_LOGGER_ERROR(
            logger, "fail to get ip string from {} family address", family);
      }
    }
  }
  freeifaddrs(ifaddr);
}
