/*
// 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 <phosphor-logging/lg2.hpp>

#include <charconv>

/* Hacks from splitting entity_manager.cpp */
// NOLINTBEGIN(cppcoreguidelines-avoid-non-const-global-variables)
extern std::shared_ptr<sdbusplus::asio::connection> systemBus;
extern nlohmann::json lastJson;
extern void propertiesChangedCallback(
    nlohmann::json& systemConfiguration,
    sdbusplus::asio::object_server& objServer);
// NOLINTEND(cppcoreguidelines-avoid-non-const-global-variables)

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

constexpr const int32_t maxMapperDepth = 0;

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);
}

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);
}

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
    // 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());
}

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();
    }
    else
    {
        _callback();
    }
}
