/*
// Copyright (c) 2018 Intel Corporation
//
// 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.
*/
/// \file perform_scan.cpp
#include "entity_manager.hpp"

#include <boost/algorithm/string/predicate.hpp>
#include <boost/asio/steady_timer.hpp>
#include <boost/container/flat_map.hpp>
#include <boost/container/flat_set.hpp>

#include <charconv>

/* Hacks from splitting entity_manager.cpp */
extern std::shared_ptr<sdbusplus::asio::connection> systemBus;
extern nlohmann::json lastJson;
extern void
    propertiesChangedCallback(nlohmann::json& systemConfiguration,
                              sdbusplus::asio::object_server& objServer);

using GetSubTreeType = std::vector<
    std::pair<std::string,
              std::vector<std::pair<std::string, std::vector<std::string>>>>>;

constexpr const int32_t maxMapperDepth = 0;

constexpr const bool debug = false;

struct DBusInterfaceInstance
{
    std::string busName;
    std::string path;
    std::string interface;
};

void getInterfaces(
    const DBusInterfaceInstance& instance,
    const std::vector<std::shared_ptr<PerformProbe>>& probeVector,
    const std::shared_ptr<PerformScan>& scan, size_t retries = 5)
{
    if (retries == 0U)
    {
        std::cerr << "retries exhausted on " << instance.busName << " "
                  << instance.path << " " << instance.interface << "\n";
        return;
    }

    systemBus->async_method_call(
        [instance, scan, probeVector, retries](boost::system::error_code& errc,
                                               const DBusInterface& resp) {
        if (errc)
        {
            std::cerr << "error calling getall on  " << instance.busName << " "
                      << instance.path << " " << instance.interface << "\n";

            auto timer = std::make_shared<boost::asio::steady_timer>(io);
            timer->expires_after(std::chrono::seconds(2));

            timer->async_wait([timer, instance, scan, probeVector,
                               retries](const boost::system::error_code&) {
                getInterfaces(instance, probeVector, scan, retries - 1);
            });
            return;
        }

        scan->dbusProbeObjects[instance.path][instance.interface] = resp;
        },
        instance.busName, instance.path, "org.freedesktop.DBus.Properties",
        "GetAll", instance.interface);

    if constexpr (debug)
    {
        std::cerr << __LINE__ << "\n";
    }
}

static void registerCallback(nlohmann::json& systemConfiguration,
                             sdbusplus::asio::object_server& objServer,
                             const std::string& path)
{
    static boost::container::flat_map<std::string, sdbusplus::bus::match_t>
        dbusMatches;

    auto find = dbusMatches.find(path);
    if (find != dbusMatches.end())
    {
        return;
    }

    std::function<void(sdbusplus::message_t & message)> eventHandler =
        [&](sdbusplus::message_t&) {
        propertiesChangedCallback(systemConfiguration, objServer);
    };

    sdbusplus::bus::match_t match(
        static_cast<sdbusplus::bus_t&>(*systemBus),
        "type='signal',member='PropertiesChanged',path='" + path + "'",
        eventHandler);
    dbusMatches.emplace(path, std::move(match));
}

static void
    processDbusObjects(std::vector<std::shared_ptr<PerformProbe>>& probeVector,
                       const std::shared_ptr<PerformScan>& scan,
                       const GetSubTreeType& interfaceSubtree)
{
    for (const auto& [path, object] : interfaceSubtree)
    {
        // Get a PropertiesChanged callback for all interfaces on this path.
        registerCallback(scan->_systemConfiguration, scan->objServer, path);

        for (const auto& [busname, ifaces] : object)
        {
            for (const std::string& iface : ifaces)
            {
                // The 3 default org.freedeskstop interfaces (Peer,
                // Introspectable, and Properties) are returned by
                // the mapper but don't have properties, so don't bother
                // with the GetAll call to save some cycles.
                if (!boost::algorithm::starts_with(iface, "org.freedesktop"))
                {
                    getInterfaces({busname, path, iface}, probeVector, scan);
                }
            }
        }
    }
}

// Populates scan->dbusProbeObjects with all interfaces and properties
// for the paths that own the interfaces passed in.
void findDbusObjects(std::vector<std::shared_ptr<PerformProbe>>&& probeVector,
                     boost::container::flat_set<std::string>&& interfaces,
                     const std::shared_ptr<PerformScan>& scan,
                     size_t retries = 5)
{
    // Filter out interfaces already obtained.
    for (const auto& [path, probeInterfaces] : scan->dbusProbeObjects)
    {
        for (const auto& [interface, _] : probeInterfaces)
        {
            interfaces.erase(interface);
        }
    }
    if (interfaces.empty())
    {
        return;
    }

    // find all connections in the mapper that expose a specific type
    systemBus->async_method_call(
        [interfaces, probeVector{std::move(probeVector)}, scan,
         retries](boost::system::error_code& ec,
                  const GetSubTreeType& interfaceSubtree) mutable {
        if (ec)
        {
            if (ec.value() == ENOENT)
            {
                return; // wasn't found by mapper
            }
            std::cerr << "Error communicating to mapper.\n";

            if (retries == 0U)
            {
                // if we can't communicate to the mapper something is very
                // wrong
                std::exit(EXIT_FAILURE);
            }

            auto timer = std::make_shared<boost::asio::steady_timer>(io);
            timer->expires_after(std::chrono::seconds(10));

            timer->async_wait([timer, interfaces{std::move(interfaces)}, scan,
                               probeVector{std::move(probeVector)}, retries](
                                  const boost::system::error_code&) mutable {
                findDbusObjects(std::move(probeVector), std::move(interfaces),
                                scan, retries - 1);
            });
            return;
        }

        processDbusObjects(probeVector, scan, interfaceSubtree);
        },
        "xyz.openbmc_project.ObjectMapper",
        "/xyz/openbmc_project/object_mapper",
        "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", maxMapperDepth,
        interfaces);

    if constexpr (debug)
    {
        std::cerr << __LINE__ << "\n";
    }
}

static std::string getRecordName(const DBusInterface& probe,
                                 const std::string& probeName)
{
    if (probe.empty())
    {
        return probeName;
    }

    // use an array so alphabetical order from the flat_map is maintained
    auto device = nlohmann::json::array();
    for (const auto& devPair : probe)
    {
        device.push_back(devPair.first);
        std::visit([&device](auto&& v) { device.push_back(v); },
                   devPair.second);
    }

    // hashes are hard to distinguish, use the non-hashed version if we want
    // debug
    if constexpr (debug)
    {
        return probeName + device.dump();
    }

    return std::to_string(std::hash<std::string>{}(probeName + device.dump()));
}

PerformScan::PerformScan(nlohmann::json& systemConfiguration,
                         nlohmann::json& missingConfigurations,
                         std::list<nlohmann::json>& configurations,
                         sdbusplus::asio::object_server& objServerIn,
                         std::function<void()>&& callback) :
    _systemConfiguration(systemConfiguration),
    _missingConfigurations(missingConfigurations),
    _configurations(configurations), objServer(objServerIn),
    _callback(std::move(callback))
{}

static void pruneRecordExposes(nlohmann::json& record)
{
    auto findExposes = record.find("Exposes");
    if (findExposes == record.end())
    {
        return;
    }

    auto copy = nlohmann::json::array();
    for (auto& expose : *findExposes)
    {
        if (!expose.is_null())
        {
            copy.emplace_back(expose);
        }
    }
    *findExposes = copy;
}

static void recordDiscoveredIdentifiers(std::set<nlohmann::json>& usedNames,
                                        std::list<size_t>& indexes,
                                        const std::string& probeName,
                                        const nlohmann::json& record)
{
    size_t indexIdx = probeName.find('$');
    if (indexIdx == std::string::npos)
    {
        return;
    }

    auto nameIt = record.find("Name");
    if (nameIt == record.end())
    {
        std::cerr << "Last JSON Illegal\n";
        return;
    }

    int index = 0;
    auto str = nameIt->get<std::string>().substr(indexIdx);
    // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
    const char* endPtr = str.data() + str.size();
    auto [p, ec] = std::from_chars(str.data(), endPtr, index);
    if (ec != std::errc())
    {
        return; // non-numeric replacement
    }

    usedNames.insert(nameIt.value());

    auto usedIt = std::find(indexes.begin(), indexes.end(), index);
    if (usedIt != indexes.end())
    {
        indexes.erase(usedIt);
    }
}

static bool extractExposeActionRecordNames(std::vector<std::string>& matches,
                                           nlohmann::json::iterator& keyPair)
{
    if (keyPair.value().is_string())
    {
        matches.emplace_back(keyPair.value());
        return true;
    }

    if (keyPair.value().is_array())
    {
        for (const auto& value : keyPair.value())
        {
            if (!value.is_string())
            {
                std::cerr << "Value is invalid type " << value << "\n";
                break;
            }
            matches.emplace_back(value);
        }

        return true;
    }

    std::cerr << "Value is invalid type " << keyPair.key() << "\n";

    return false;
}

static std::optional<std::vector<std::string>::iterator>
    findExposeActionRecord(std::vector<std::string>& matches,
                           const nlohmann::json& record)
{
    const auto& name = (record)["Name"].get_ref<const std::string&>();
    auto compare = [&name](const std::string& s) { return s == name; };
    auto matchIt = std::find_if(matches.begin(), matches.end(), compare);

    if (matchIt == matches.end())
    {
        return std::nullopt;
    }

    return matchIt;
}

static void applyBindExposeAction(nlohmann::json& exposedObject,
                                  nlohmann::json& expose,
                                  const std::string& propertyName)
{
    if (boost::starts_with(propertyName, "Bind"))
    {
        std::string bind = propertyName.substr(sizeof("Bind") - 1);
        exposedObject["Status"] = "okay";
        expose[bind] = exposedObject;
    }
}

static void applyDisableExposeAction(nlohmann::json& exposedObject,
                                     const std::string& propertyName)
{
    if (propertyName == "DisableNode")
    {
        exposedObject["Status"] = "disabled";
    }
}

static void applyConfigExposeActions(std::vector<std::string>& matches,
                                     nlohmann::json& expose,
                                     const std::string& propertyName,
                                     nlohmann::json& configExposes)
{
    for (auto& exposedObject : configExposes)
    {
        auto match = findExposeActionRecord(matches, exposedObject);
        if (match)
        {
            matches.erase(*match);
            applyBindExposeAction(exposedObject, expose, propertyName);
            applyDisableExposeAction(exposedObject, propertyName);
        }
    }
}

static void applyExposeActions(nlohmann::json& systemConfiguration,
                               const std::string& recordName,
                               nlohmann::json& expose,
                               nlohmann::json::iterator& keyPair)
{
    bool isBind = boost::starts_with(keyPair.key(), "Bind");
    bool isDisable = keyPair.key() == "DisableNode";
    bool isExposeAction = isBind || isDisable;

    if (!isExposeAction)
    {
        return;
    }

    std::vector<std::string> matches;

    if (!extractExposeActionRecordNames(matches, keyPair))
    {
        return;
    }

    for (const auto& [configId, config] : systemConfiguration.items())
    {
        // don't disable ourselves
        if (isDisable && configId == recordName)
        {
            continue;
        }

        auto configListFind = config.find("Exposes");
        if (configListFind == config.end())
        {
            continue;
        }

        if (!configListFind->is_array())
        {
            continue;
        }

        applyConfigExposeActions(matches, expose, keyPair.key(),
                                 *configListFind);
    }

    if (!matches.empty())
    {
        std::cerr << "configuration file dependency error, could not find "
                  << keyPair.key() << " " << keyPair.value() << "\n";
    }
}

static std::string generateDeviceName(const std::set<nlohmann::json>& usedNames,
                                      const DBusObject& dbusObject,
                                      size_t foundDeviceIdx,
                                      const std::string& nameTemplate,
                                      std::optional<std::string>& replaceStr)
{
    nlohmann::json copyForName = {{"Name", nameTemplate}};
    nlohmann::json::iterator copyIt = copyForName.begin();
    std::optional<std::string> replaceVal =
        templateCharReplace(copyIt, dbusObject, foundDeviceIdx, replaceStr);

    if (!replaceStr && replaceVal)
    {
        if (usedNames.find(copyIt.value()) != usedNames.end())
        {
            replaceStr = replaceVal;
            copyForName = {{"Name", nameTemplate}};
            copyIt = copyForName.begin();
            templateCharReplace(copyIt, dbusObject, foundDeviceIdx, replaceStr);
        }
    }

    if (replaceStr)
    {
        std::cerr << "Duplicates found, replacing " << *replaceStr
                  << " with found device index.\n Consider "
                     "fixing template to not have duplicates\n";
    }

    return copyIt.value();
}

void PerformScan::updateSystemConfiguration(const nlohmann::json& recordRef,
                                            const std::string& probeName,
                                            FoundDevices& foundDevices)
{
    _passed = true;
    passedProbes.push_back(probeName);

    std::set<nlohmann::json> usedNames;
    std::list<size_t> indexes(foundDevices.size());
    std::iota(indexes.begin(), indexes.end(), 1);

    // copy over persisted configurations and make sure we remove
    // indexes that are already used
    for (auto itr = foundDevices.begin(); itr != foundDevices.end();)
    {
        std::string recordName = getRecordName(itr->interface, probeName);

        auto record = _systemConfiguration.find(recordName);
        if (record == _systemConfiguration.end())
        {
            record = lastJson.find(recordName);
            if (record == lastJson.end())
            {
                itr++;
                continue;
            }

            pruneRecordExposes(*record);

            _systemConfiguration[recordName] = *record;
        }
        _missingConfigurations.erase(recordName);

        // We've processed the device, remove it and advance the
        // iterator
        itr = foundDevices.erase(itr);
        recordDiscoveredIdentifiers(usedNames, indexes, probeName, *record);
    }

    std::optional<std::string> replaceStr;

    DBusObject emptyObject;
    DBusInterface emptyInterface;
    emptyObject.emplace(std::string{}, emptyInterface);

    for (const auto& [foundDevice, path] : foundDevices)
    {
        // Need all interfaces on this path so that template
        // substitutions can be done with any of the contained
        // properties.  If the probe that passed didn't use an
        // interface, such as if it was just TRUE, then
        // templateCharReplace will just get passed in an empty
        // map.
        auto objectIt = dbusProbeObjects.find(path);
        const DBusObject& dbusObject = (objectIt == dbusProbeObjects.end())
                                           ? emptyObject
                                           : objectIt->second;

        nlohmann::json record = recordRef;
        std::string recordName = getRecordName(foundDevice, probeName);
        size_t foundDeviceIdx = indexes.front();
        indexes.pop_front();

        // check name first so we have no duplicate names
        auto getName = record.find("Name");
        if (getName == record.end())
        {
            std::cerr << "Record Missing Name! " << record.dump();
            continue; // this should be impossible at this level
        }

        std::string deviceName = generateDeviceName(
            usedNames, dbusObject, foundDeviceIdx, getName.value(), replaceStr);
        getName.value() = deviceName;
        usedNames.insert(deviceName);

        for (auto keyPair = record.begin(); keyPair != record.end(); keyPair++)
        {
            if (keyPair.key() != "Name")
            {
                templateCharReplace(keyPair, dbusObject, foundDeviceIdx,
                                    replaceStr);
            }
        }

        // insert into configuration temporarily to be able to
        // reference ourselves

        _systemConfiguration[recordName] = record;

        auto findExpose = record.find("Exposes");
        if (findExpose == record.end())
        {
            continue;
        }

        for (auto& expose : *findExpose)
        {
            for (auto keyPair = expose.begin(); keyPair != expose.end();
                 keyPair++)
            {
                templateCharReplace(keyPair, dbusObject, foundDeviceIdx,
                                    replaceStr);

                applyExposeActions(_systemConfiguration, recordName, expose,
                                   keyPair);
            }
        }

        // overwrite ourselves with cleaned up version
        _systemConfiguration[recordName] = record;
        _missingConfigurations.erase(recordName);
    }
}

void PerformScan::run()
{
    boost::container::flat_set<std::string> dbusProbeInterfaces;
    std::vector<std::shared_ptr<PerformProbe>> dbusProbePointers;

    for (auto it = _configurations.begin(); it != _configurations.end();)
    {
        // check for poorly formatted fields, probe must be an array
        auto findProbe = it->find("Probe");
        if (findProbe == it->end())
        {
            std::cerr << "configuration file missing probe:\n " << *it << "\n";
            it = _configurations.erase(it);
            continue;
        }

        auto findName = it->find("Name");
        if (findName == it->end())
        {
            std::cerr << "configuration file missing name:\n " << *it << "\n";
            it = _configurations.erase(it);
            continue;
        }
        std::string probeName = *findName;

        if (std::find(passedProbes.begin(), passedProbes.end(), probeName) !=
            passedProbes.end())
        {
            it = _configurations.erase(it);
            continue;
        }

        nlohmann::json& recordRef = *it;
        nlohmann::json probeCommand;
        if ((*findProbe).type() != nlohmann::json::value_t::array)
        {
            probeCommand = nlohmann::json::array();
            probeCommand.push_back(*findProbe);
        }
        else
        {
            probeCommand = *findProbe;
        }

        // store reference to this to children to makes sure we don't get
        // destroyed too early
        auto thisRef = shared_from_this();
        auto probePointer = std::make_shared<PerformProbe>(
            recordRef, probeCommand, probeName, thisRef);

        // parse out dbus probes by discarding other probe types, store in a
        // map
        for (const nlohmann::json& probeJson : probeCommand)
        {
            const std::string* probe = probeJson.get_ptr<const std::string*>();
            if (probe == nullptr)
            {
                std::cerr << "Probe statement wasn't a string, can't parse";
                continue;
            }
            if (findProbeType(*probe))
            {
                continue;
            }
            // syntax requires probe before first open brace
            auto findStart = probe->find('(');
            std::string interface = probe->substr(0, findStart);
            dbusProbeInterfaces.emplace(interface);
            dbusProbePointers.emplace_back(probePointer);
        }
        it++;
    }

    // probe vector stores a shared_ptr to each PerformProbe that cares
    // about a dbus interface
    findDbusObjects(std::move(dbusProbePointers),
                    std::move(dbusProbeInterfaces), shared_from_this());
    if constexpr (debug)
    {
        std::cerr << __LINE__ << "\n";
    }
}

PerformScan::~PerformScan()
{
    if (_passed)
    {
        auto nextScan = std::make_shared<PerformScan>(
            _systemConfiguration, _missingConfigurations, _configurations,
            objServer, std::move(_callback));
        nextScan->passedProbes = std::move(passedProbes);
        nextScan->dbusProbeObjects = std::move(dbusProbeObjects);
        nextScan->run();

        if constexpr (debug)
        {
            std::cerr << __LINE__ << "\n";
        }
    }
    else
    {
        _callback();

        if constexpr (debug)
        {
            std::cerr << __LINE__ << "\n";
        }
    }
}
