/*
// Copyright (c) 2019 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.
*/

#include "MctpEndpoint.hpp"
#include "MctpReactorDevice.hpp"
#include "NVMeBasic.hpp"
#include "NVMeIntf.hpp"
#include "NVMeMi.hpp"
#include "NVMePlugin.hpp"
#include "NVMeSubsys.hpp"

#include <dlfcn.h>

#include <boost/algorithm/string.hpp>
#include <boost/asio/steady_timer.hpp>
#include <phosphor-logging/lg2.hpp>

#include <filesystem>
#include <fstream>
#include <optional>
#include <regex>
#include <system_error>
#include <unordered_set>

struct NVMeDevice
{
    std::shared_ptr<MctpDevice> dev;
    NVMeIntf intf;
    std::shared_ptr<NVMeSubsystem> subsys;
    bool enableFeatureLockdown = false;
};

// a map with key value of {path, NVMeSubsystem}
using NVMEMap = std::map<std::string, NVMeDevice>;
static NVMEMap nvmeDevices;

// A map from root bus number to the Worker
// This map means to reuse the same worker for all NVMe EP under the same
// I2C root bus. There is no real physical concurrency among the i2c/mctp
// devices on the same bus. Though mctp kernel drive can schedule and
// sequencialize the transactions but assigning individual worker thread to
// each EP makes no sense.
static std::map<int, std::weak_ptr<NVMeMiWorker>> i2cWorkerMap{};

std::unordered_map<std::string, void*> pluginLibMap = {};

static std::unordered_set<int> bannedBuses;

static void initBannedI2cBus()
{
    const std::string script = "/usr/bin/init-banned-i2c-bus.sh";
    const std::string confPath = "/var/run/nvmed/banned-i2c-bus.conf";
    if (!std::filesystem::exists(script))
    {
        lg2::error("Script {SCRIPT} doesn't exist", "SCRIPT", script);
        return;
    }

    lg2::info("Begin to execute {SCRIPT}", "SCRIPT", script);
    // TODO: (b/376270522) cert-env33-c error: calling 'system' uses a command
    // processor
    int rc = std::system(script.c_str()); // NOLINT(cert-env33-c)
    lg2::info("Shell script rc = {RC}", "RC", rc);

    if (!std::filesystem::exists(confPath))
    {
        lg2::warning("Warning: {CONF_PATH} doesn't exist.", "CONF_PATH",
                     confPath);
        // Be optimistic，assume no bus is banned
        return;
    }
    std::ifstream file;
    file.open(confPath);
    if (!file.is_open())
    {
        lg2::error("Error: cannot open {CONF_PATH}", "CONF_PATH", confPath);
        // Be optimistic，assume no bus is banned
        return;
    }

    bannedBuses.clear();
    int i2cBus{0};
    while (file >> i2cBus)
    {
        lg2::info("Banned i2c bus: {BUS}", "BUS", i2cBus);
        bannedBuses.insert(i2cBus);
    }
    file.close();
}

static std::optional<int>
    extractBusNumber(const std::string& path,
                     const SensorBaseConfigMap& properties)
{
    auto findBus = properties.find("Bus");
    if (findBus == properties.end())
    {
        lg2::error("could not determine bus number for '{PATH}'", "PATH", path);
        return std::nullopt;
    }

    return std::visit(VariantToIntVisitor(), findBus->second);
}

static std::optional<int> extractAddress(const std::string& path,
                                         const SensorBaseConfigMap& properties)
{
    auto findAddr = properties.find("Address");
    if (findAddr == properties.end())
    {
        lg2::error("could not determine address for '{PATH}'", "PATH", path);
        return std::nullopt;
    }

    return std::visit(VariantToIntVisitor(), findAddr->second);
}

static std::optional<std::string>
    extractName(const std::string& path, const SensorBaseConfigMap& properties)
{
    auto findName = properties.find("Name");
    if (findName == properties.end())
    {
        lg2::error("could not determine configuration name for '{PATH}'",
                   "PATH", path);
        return std::nullopt;
    }

    return std::get<std::string>(findName->second);
}

static std::optional<std::string>
    extractProtocol(const std::string& path,
                    const SensorBaseConfigMap& properties)
{
    auto findProtocol = properties.find("Protocol");
    if (findProtocol == properties.end())
    {
        lg2::error("could not determine nvme protocol for '{PATH}'", "PATH",
                   path);
        return std::nullopt;
    }
    return std::get<std::string>(findProtocol->second);
}

static std::optional<std::string>
    extractMctpReactorConfigPath(const SensorBaseConfigMap& properties)
{
    auto findMctpReactorConfigPath = properties.find("MctpReactorConfigPath");
    if (findMctpReactorConfigPath == properties.end())
    {
        return std::nullopt;
    }
    return std::get<std::string>(findMctpReactorConfigPath->second);
}

static bool hasLockdownFeature(const std::string& path,
                               const SensorBaseConfigMap& properties)
{
    auto it = properties.find("SupportedFeatures");
    if (it == properties.end())
    {
        return false;
    }

    const auto& value = it->second;

    if (std::holds_alternative<std::vector<std::string>>(value))
    {
        const auto& features =
            std::get<std::vector<std::string>>(value); // Safe now
        for (const auto& feature : features)
        {
            if (feature == "Lockdown")
            {
                return true;
            }
        }
    }
    else
    {
        lg2::warning(
            "'{PATH}': 'SupportedFeatures' is not an array of strings.", "PATH",
            path);
    }
    return false;
}

static void
    setupMctpDevice(const std::shared_ptr<MctpDevice>& dev,
                    const std::weak_ptr<NVMeMiIntf>& weakIntf,
                    const std::weak_ptr<NVMeSubsystem>& weakSubsys,
                    const std::shared_ptr<boost::asio::steady_timer>& timer)
{
    dev->setup([weakDev{std::weak_ptr(dev)}, weakIntf, weakSubsys,
                timer](const std::error_code& ec,
                       const std::shared_ptr<MctpEndpoint>& ep) {
        if (ec)
        {
            auto dev = weakDev.lock();
            if (!dev)
            {
                return;
            }
            // Setup failed, wait a bit and try again
            timer->expires_from_now(std::chrono::seconds(5));
            timer->async_wait([=](const boost::system::error_code& ec) {
                if (!ec)
                {
                    setupMctpDevice(dev, weakIntf, weakSubsys, timer);
                }
            });
            return;
        }

        ep->subscribe(
            // Degraded
            [weakIntf](const std::shared_ptr<MctpEndpoint>& ep) {
            if (auto miIntf = weakIntf.lock())
            {
                std::cout << "[" << ep->describe() << "]: Degraded" << '\n';
                miIntf->stop();
            }
        },
            // Available
            [weakIntf, weakSubsys](const std::shared_ptr<MctpEndpoint>& ep) {
            if (auto miIntf = weakIntf.lock())
            {
                if (auto subsys = weakSubsys.lock())
                {
                    std::cout << subsys->getName() << " [" << ep->describe()
                              << "]: Available" << '\n';
                }
                miIntf->start(ep);
            }
        },
            // Removed
            [=](const std::shared_ptr<MctpEndpoint>& ep) {
            auto nvmeSubsys = weakSubsys.lock();
            auto miIntf = weakIntf.lock();
            auto dev = weakDev.lock();
            if (!nvmeSubsys || !miIntf || !dev)
            {
                return;
            }

            std::cout << "[" << ep->describe() << "]: Removed" << '\n';
            miIntf->stop();
            // Start polling for the return of the device
            timer->expires_from_now(std::chrono::seconds(5));
            timer->async_wait([=](const boost::system::error_code& ec) {
                if (!ec)
                {
                    setupMctpDevice(dev, weakIntf, weakSubsys, timer);
                }
            });
        });

        auto miIntf = weakIntf.lock();
        auto nvmeSubsys = weakSubsys.lock();
        if (miIntf && nvmeSubsys)
        {
            miIntf->start(ep);
        }
    });
}

static void handleConfigurations(
    boost::asio::io_context& io, sdbusplus::asio::object_server& objectServer,
    std::shared_ptr<sdbusplus::asio::connection>& dbusConnection,
    const ManagedObjectType& nvmeConfigurations)
{
    // Initialize banned i2c bus info on every configuration change
    initBannedI2cBus();

    /* We perform two iterations for configurations here. The first iteration is
     * to set up NVMeIntf. The second iter is to setup NVMe subsystem.
     *
     * The reason to seperate these two processes is NVMeIntf initialization of
     * NVMeMI is via MCTPd, from which the mctp control msg should be relatively
     * short and should not be delayed by NVMe-MI protocol msg from NVMe
     * subsystem.
     */
    std::map<std::string, NVMeDevice> updatedDevices;
    for (const auto& [nvmeObjectPath, configData] : nvmeConfigurations)
    {
        // find base configuration
        auto sensorBase =
            configData.find(configInterfaceName(nvme::sensorType));
        if (sensorBase == configData.end())
        {
            continue;
        }

        const SensorBaseConfigMap& sensorConfig = sensorBase->second;
        std::optional<int> busNumber = extractBusNumber(nvmeObjectPath,
                                                        sensorConfig);
        std::optional<int> address = extractAddress(nvmeObjectPath,
                                                    sensorConfig);
        std::optional<std::string> sensorName = extractName(nvmeObjectPath,
                                                            sensorConfig);
        std::optional<std::string> nvmeProtocol =
            extractProtocol(nvmeObjectPath, sensorConfig);
        std::optional<std::string> mctpReactorConfigPath =
            extractMctpReactorConfigPath(sensorConfig);

        bool enableFeatureLockdown = hasLockdownFeature(nvmeObjectPath,
                                                        sensorConfig);

        if (!sensorName)
        {
            continue;
        }

        const bool isMctpReactorDevice = mctpReactorConfigPath.has_value();

        // Some NVMe devices are accessible over I2C because they're connected
        // over SMBus directly to the BMC. In other cases, they might be
        // connected to the BMC through a bridge (such as
        // MCTP USB <-> I2C bridge).
        const bool isI2cAccessible = busNumber.has_value();

        // If a device is not an mctpreactor device, it must be accessible over
        // I2C directly.
        if (!isMctpReactorDevice && !isI2cAccessible)
        {
            lg2::info("Found an mctpd device that isn't I2C accessible,"
                      "but it must be: {PATH}",
                      "PATH", nvmeObjectPath.str);
            continue;
        }

        if (busNumber && bannedBuses.contains(*busNumber))
        {
            lg2::info("Skip banned i2c bus: {BUS}", "BUS", *busNumber);
            continue;
        }

        // the default protocol is mi_basic
        if (!nvmeProtocol)
        {
            nvmeProtocol.emplace("mi_basic");
        }

        // Support for non-I2C-accessible devices doesn't exist for mi_basic
        // protocol because we don't need it for now.
        if (*nvmeProtocol == "mi_basic" && !isI2cAccessible)
        {
            lg2::info("Skipping an mi_basic device that's not accessible "
                      "over i2c bus.");
            continue;
        }

        if (*nvmeProtocol == "mi_basic")
        {
            // defualt i2c basic port is 0x6a
            if (!address)
            {
                address.emplace(0x6a);
            }
            try
            {
                NVMeIntf nvmeBasic = NVMeIntf::create<NVMeBasic>(io, *busNumber,
                                                                 *address);

                NVMeDevice dev{{}, nvmeBasic, {}, enableFeatureLockdown};
                updatedDevices.emplace(nvmeObjectPath, std::move(dev));
            }
            catch (std::exception& ex)
            {
                lg2::error(
                    "Failed to add nvme basic interface for '{PATH}': {ERROR}",
                    "PATH", nvmeObjectPath.str, "ERROR", ex.what());
                continue;
            }
        }
        else if (*nvmeProtocol == "mi_i2c")
        {
            // defualt i2c nvme-mi port is 0x1d
            if (!address)
            {
                address.emplace(0x1d);
            }
            PowerState powerState = getPowerState(sensorConfig);

            std::shared_ptr<NVMeMiWorker> worker;
            if (singleWorkerFeature && isI2cAccessible)
            {
                auto root = deriveRootBus(*busNumber);

                if (!root || *root < 0)
                {
                    throw std::runtime_error("invalid root bus number");
                }
                auto res = i2cWorkerMap.find(*root);

                if (res == i2cWorkerMap.end() || res->second.expired())
                {
                    worker = NVMeMiWorker::create(io);
                    i2cWorkerMap[*root] = worker;
                }
                else
                {
                    worker = res->second.lock();
                }
            }
            else
            {
                worker = NVMeMiWorker::create(io);
            }

            try
            {
                // Note that in this codepath, despite using "mi_i2c" protocol,
                // we can be talking to NVMe devices not accessible through I2C
                // directly.
                std::shared_ptr<MctpDevice> mctpDev;
                if (!isMctpReactorDevice)
                {
                    mctpDev = std::make_shared<SmbusMctpdDevice>(
                        dbusConnection, *busNumber, *address);
                }
                else // isMctpReactorDevice
                {
                    mctpDev = std::make_shared<MctpReactorDevice>(
                        dbusConnection, *mctpReactorConfigPath, busNumber,
                        address);
                }

                NVMeIntf nvmeMi = NVMeIntf::create<NVMeMi>(
                    io, dbusConnection, mctpDev, worker, powerState);

                auto nvme = std::get<std::shared_ptr<NVMeMiIntf>>(
                    nvmeMi.getInferface());
                // Create a partial NVMeDevice entry in the temporary
                // updatedDevices map
                NVMeDevice nvmeDev{mctpDev, nvmeMi, {}, enableFeatureLockdown};
                updatedDevices.emplace(nvmeObjectPath, std::move(nvmeDev));
            }
            catch (std::exception& ex)
            {
                lg2::error(
                    "Failed to add nvme mi interface for '{PATH}': {ERROR}",
                    "PATH", nvmeObjectPath.str, "ERROR", ex.what());
                continue;
            }
        }
    }

    for (const auto& [interfacePath, configData] : nvmeConfigurations)
    {
        // find base configuration
        auto sensorBase =
            configData.find(configInterfaceName(nvme::sensorType));
        if (sensorBase == configData.end())
        {
            continue;
        }

        const SensorBaseConfigMap& sensorConfig = sensorBase->second;

        std::optional<std::string> sensorName = extractName(interfacePath,
                                                            sensorConfig);

        auto find = updatedDevices.find(interfacePath);
        if (find == updatedDevices.end())
        {
            continue;
        }
        try
        {
            bool lockdownFeature = find->second.enableFeatureLockdown;

            auto nvmeSubsys = NVMeSubsystem::create(
                io, objectServer, dbusConnection, interfacePath, *sensorName,
                configData, find->second.intf, lockdownFeature);
            // Complete the NVMeDevice entry with its subsystem and record it in
            // the persistent nvmeDeviceMap
            find->second.subsys = nvmeSubsys;
            auto [entry, _] = nvmeDevices.emplace(interfacePath,
                                                  std::move(find->second));
            auto nvmeDev = entry->second;
            nvmeSubsys->start();
            if (nvmeDev.intf.getProtocol() != NVMeIntf::Protocol::NVMeMI)
            {
                continue;
            }

            auto miIntf = std::get<std::shared_ptr<NVMeMiIntf>>(
                nvmeDev.intf.getInferface());
            auto timer = std::make_shared<boost::asio::steady_timer>(
                io, std::chrono::seconds(5));
            setupMctpDevice(nvmeDev.dev, miIntf, nvmeSubsys, timer);
        }
        catch (std::exception& ex)
        {
            lg2::error("Failed to add nvme subsystem for '{PATH}': {ERROR}",
                       "PATH", std::string(interfacePath), "ERROR", ex.what());
            continue;
        }
    }
}

void createNVMeSubsystems(
    boost::asio::io_context& io, sdbusplus::asio::object_server& objectServer,
    std::shared_ptr<sdbusplus::asio::connection>& dbusConnection)
{
    // todo: it'd be better to only update the ones we care about
    for (const auto& [_, nvmeDev] : nvmeDevices)
    {
        if (nvmeDev.subsys)
        {
            nvmeDev.subsys->stop();
        }
    }
    nvmeDevices.clear();

    static int count = 0;
    static ManagedObjectType configs;
    count += 2;

    auto getter = std::make_shared<GetSensorConfiguration>(
        dbusConnection, [&io, &objectServer, &dbusConnection](
                            const ManagedObjectType& nvmeConfigurations) {
        configs = nvmeConfigurations;
        count--;
        if (count == 0)
        {
            handleConfigurations(io, objectServer, dbusConnection, configs);
        }
        else
        {
            lg2::error("more than one `handleConfigurations` has been "
                       "scheduled, cancel the current one");
        }
    });
    auto timer = std::make_shared<boost::asio::steady_timer>(
        io, std::chrono::seconds(5));
    timer->async_wait([&io, &objectServer, &dbusConnection,
                       timer](const boost::system::error_code& ec) {
        count--;
        if (ec)
        {
            return;
        }
        if (count == 0)
        {
            handleConfigurations(io, objectServer, dbusConnection, configs);
        }
        else
        {
            lg2::error("`handleConfigurations` has not been triggered, "
                       "cancel the timer");
        }
    });

    getter->getConfiguration(std::vector<std::string>{nvme::sensorType});
}

static void interfaceRemoved(sdbusplus::message_t& message, NVMEMap& devices)
{
    if (message.is_method_error())
    {
        lg2::error("interfacesRemoved callback method error");
        return;
    }

    sdbusplus::message::object_path path;
    std::vector<std::string> interfaces;

    message.read(path, interfaces);

    auto interface = std::find(interfaces.begin(), interfaces.end(),
                               configInterfaceName(nvme::sensorType));
    if (interface == interfaces.end())
    {
        return;
    }

    auto device = devices.find(path);
    if (device == devices.end())
    {
        return;
    }

    device->second.subsys->stop();
    devices.erase(device);
}

int main()
{
    if (singleWorkerFeature)
    {
        lg2::info("singleWorkerFeature on");
    }

    // Load plugin shared libraries
    try
    {
        for (const auto& entry :
             std::filesystem::directory_iterator(NVMePlugin::libraryPath))
        {
            void* lib = dlopen(entry.path().c_str(), RTLD_NOW);
            if (lib != nullptr)
            {
                pluginLibMap.emplace(entry.path().filename().string(), lib);
            }
            else
            {
                lg2::error("could not load the plugin: {ERROR}", "ERROR",
                           dlerror());
            }
        }
    }
    catch (const std::filesystem::filesystem_error& e)
    {
        lg2::error("failed to open plugin folder: {ERROR}", "ERROR", e.what());
    }

    // TODO: set single thread mode according to input parameters

    boost::asio::io_context io;
    auto systemBus = std::make_shared<sdbusplus::asio::connection>(io);
    systemBus->request_name("xyz.openbmc_project.NVMe");
    sdbusplus::asio::object_server objectServer(systemBus, true);
    objectServer.add_manager("/xyz/openbmc_project/sensors");
    objectServer.add_manager("/xyz/openbmc_project/inventory");

    io.post([&]() { createNVMeSubsystems(io, objectServer, systemBus); });

    boost::asio::steady_timer filterTimer(io);
    std::function<void(sdbusplus::message_t&)> eventHandler =
        [&filterTimer, &io, &objectServer, &systemBus](sdbusplus::message_t&) {
        // this implicitly cancels the timer
        filterTimer.expires_after(std::chrono::seconds(1));

        filterTimer.async_wait([&](const boost::system::error_code& ec) {
            if (ec == boost::asio::error::operation_aborted)
            {
                return; // we're being canceled
            }

            if (ec)
            {
                lg2::error("Error: {ERROR}", "ERROR", ec.message());
                return;
            }

            createNVMeSubsystems(io, objectServer, systemBus);
        });
    };

    std::vector<std::unique_ptr<sdbusplus::bus::match_t>> matches =
        setupPropertiesChangedMatches(
            *systemBus, std::to_array<const char*>({NVMeSensor::sensorType}),
            eventHandler);

    // Watch for entity-manager to remove configuration interfaces
    // so the corresponding sensors can be removed.
    auto ifaceRemovedMatch = std::make_unique<sdbusplus::bus::match_t>(
        static_cast<sdbusplus::bus_t&>(*systemBus),
        "type='signal',member='InterfacesRemoved',arg0path='" +
            std::string(inventoryPath) + "/'",
        [](sdbusplus::message_t& msg) { interfaceRemoved(msg, nvmeDevices); });

    setupManufacturingModeMatch(*systemBus);

    // The NVMe controller used pipe to transfer raw data. The pipe could be
    // closed by the client. It should not be considered as an error.
    boost::asio::signal_set signals(io, SIGPIPE);
    signals.async_wait(
        [](const boost::system::error_code& error, int signalNumber) {
        lg2::info("signal: {SIGNAL}, {ERROR}", "SIGNAL",
                  strsignal(signalNumber), "ERROR", error.message());
    });
    io.run();

    for (const auto& [_, lib] : pluginLibMap)
    {
        dlclose(lib);
    }
}
