#include "sd_event_loop.hpp"

#include "main.hpp"
#include "message_handler.hpp"

#include <error.h>
#include <netinet/in.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <systemd/sd-daemon.h>

#include <boost/asio/io_context.hpp>
#include <boost/asio/signal_set.hpp>
#include <phosphor-logging/lg2.hpp>
#include <sdbusplus/asio/sd_event.hpp>
#include <user_channel/channel_layer.hpp>

namespace eventloop
{

void EventLoop::handleRmcpPacket()
{
    try
    {
        auto channelPtr = std::make_shared<udpsocket::Channel>(udpSocket);

        // Initialize the Message Handler with the socket channel
        auto msgHandler = std::make_shared<message::Handler>(channelPtr, io);

        msgHandler->processIncoming();
    }
    catch (const std::exception& e)
    {
        lg2::error("Executing the IPMI message failed: {ERROR}", "ERROR", e);
    }
}

void EventLoop::startRmcpReceive()
{
    udpSocket->async_wait(boost::asio::socket_base::wait_read,
                          [this](const boost::system::error_code& ec) {
                              if (!ec)
                              {
                                  boost::asio::post(
                                      *io, [this]() { startRmcpReceive(); });
                                  handleRmcpPacket();
                              }
                          });
}

int EventLoop::getVLANID(const std::string channel)
{
    int vlanid = 0;
    if (channel.empty())
    {
        return 0;
    }

    sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
    // Enumerate all VLAN + ETHERNET interfaces
    auto req = bus.new_method_call(MAPPER_BUS_NAME, MAPPER_OBJ, MAPPER_INTF,
                                   "GetSubTree");
    req.append(PATH_ROOT, 0,
               std::vector<std::string>{INTF_VLAN, INTF_ETHERNET});
    ObjectTree objs;
    try
    {
        auto reply = bus.call(req);
        reply.read(objs);
    }
    catch (const std::exception& e)
    {
        lg2::error("getVLANID: failed to execute/read GetSubTree: {ERROR}",
                   "ERROR", e);
        return 0;
    }

    std::string ifService, logicalPath;
    for (const auto& [path, impls] : objs)
    {
        if (path.find(channel) == path.npos)
        {
            continue;
        }
        for (const auto& [service, intfs] : impls)
        {
            bool vlan = false;
            bool ethernet = false;
            for (const auto& intf : intfs)
            {
                if (intf == INTF_VLAN)
                {
                    vlan = true;
                }
                else if (intf == INTF_ETHERNET)
                {
                    ethernet = true;
                }
            }
            if (ifService.empty() && (vlan || ethernet))
            {
                ifService = service;
            }
            if (logicalPath.empty() && vlan)
            {
                logicalPath = path;
            }
        }
    }

    // VLAN devices will always have a separate logical object
    if (logicalPath.empty())
    {
        return 0;
    }

    Value value;
    auto method = bus.new_method_call(ifService.c_str(), logicalPath.c_str(),
                                      PROP_INTF, METHOD_GET);
    method.append(INTF_VLAN, "Id");
    try
    {
        auto method_reply = bus.call(method);
        method_reply.read(value);
    }
    catch (const std::exception& e)
    {
        lg2::error("getVLANID: failed to execute/read VLAN Id: {ERROR}",
                   "ERROR", e);
        return 0;
    }

    vlanid = std::get<uint32_t>(value);
    if ((vlanid & VLAN_VALUE_MASK) != vlanid)
    {
        lg2::error("networkd returned an invalid vlan: {VLAN}", "VLAN", vlanid);
        return 0;
    }

    return vlanid;
}

int EventLoop::setupSocket(std::shared_ptr<sdbusplus::asio::connection>& bus,
                           std::string channel, uint16_t reqPort)
{
    std::string iface = channel;
    static constexpr const char* unboundIface = "rmcpp";
    if (channel == "")
    {
        iface = channel = unboundIface;
    }
    else
    {
        // If VLANID of this channel is set, bind the socket to this
        // VLAN logic device
        auto vlanid = getVLANID(channel);
        if (vlanid)
        {
            iface = iface + "." + std::to_string(vlanid);
            lg2::debug("This channel has VLAN id: {VLAN}", "VLAN", vlanid);
        }
    }
    // Create our own socket if SysD did not supply one.
    int listensFdCount = sd_listen_fds(0);
    if (listensFdCount > 1)
    {
        lg2::error("Too many file descriptors received, listensFdCount: {FD}",
                   "FD", listensFdCount);
        return EXIT_FAILURE;
    }
    if (listensFdCount == 1)
    {
        int openFd = SD_LISTEN_FDS_START;
        if (!sd_is_socket(openFd, AF_UNSPEC, SOCK_DGRAM, -1))
        {
            lg2::error("Failed to set up systemd-passed socket: {ERROR}",
                       "ERROR", strerror(errno));
            return EXIT_FAILURE;
        }
        udpSocket = std::make_shared<boost::asio::ip::udp::socket>(
            *io, boost::asio::ip::udp::v6(), openFd);
    }
    else
    {
        // asio does not natively offer a way to bind to an interface
        // so it must be done in steps
        boost::asio::ip::udp::endpoint ep(boost::asio::ip::udp::v6(), reqPort);
        udpSocket = std::make_shared<boost::asio::ip::udp::socket>(*io);
        udpSocket->open(ep.protocol());
        // bind
        udpSocket->set_option(
            boost::asio::ip::udp::socket::reuse_address(true));
        udpSocket->bind(ep);
    }
    // SO_BINDTODEVICE
    char nameout[IFNAMSIZ];
    unsigned int lenout = sizeof(nameout);
    if ((::getsockopt(udpSocket->native_handle(), SOL_SOCKET, SO_BINDTODEVICE,
                      nameout, &lenout) == -1))
    {
        lg2::error("Failed to read bound device: {ERROR}", "ERROR",
                   strerror(errno));
    }
    if (iface != nameout && iface != unboundIface)
    {
        // SO_BINDTODEVICE
        if ((::setsockopt(udpSocket->native_handle(), SOL_SOCKET,
                          SO_BINDTODEVICE, iface.c_str(),
                          iface.size() + 1) == -1))
        {
            lg2::error("Failed to bind to requested interface: {ERROR}",
                       "ERROR", strerror(errno));
            return EXIT_FAILURE;
        }
        lg2::info("Bind to interface: {INTERFACE}", "INTERFACE", iface);
    }
    // cannot be constexpr because it gets passed by address
    const int option_enabled = 1;
    // common socket stuff; set options to get packet info (DST addr)
    ::setsockopt(udpSocket->native_handle(), IPPROTO_IP, IP_PKTINFO,
                 &option_enabled, sizeof(option_enabled));
    ::setsockopt(udpSocket->native_handle(), IPPROTO_IPV6, IPV6_RECVPKTINFO,
                 &option_enabled, sizeof(option_enabled));

    // set the dbus name
    std::string busName = "xyz.openbmc_project.Ipmi.Channel." + channel;
    try
    {
        bus->request_name(busName.c_str());
    }
    catch (const std::exception& e)
    {
        lg2::error("Failed to acquire D-Bus name: {NAME}: {ERROR}", "NAME",
                   busName, "ERROR", e);
        return EXIT_FAILURE;
    }
    return 0;
}

int EventLoop::startEventLoop()
{
    // set up boost::asio signal handling
    boost::asio::signal_set signals(*io, SIGINT, SIGTERM);
    signals.async_wait([this](const boost::system::error_code& /* error */,
                              int /* signalNumber */) {
        udpSocket->cancel();
        udpSocket->close();
        io->stop();
    });

    startRmcpReceive();

    io->run();

    return EXIT_SUCCESS;
}

} // namespace eventloop
