/**
 * Copyright © 2022 IBM 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 "config.h"

#include "manager.hpp"

#include "action.hpp"
#include "dbus_paths.hpp"
#include "event.hpp"
#include "fan.hpp"
#include "group.hpp"
#include "json_config.hpp"
#include "power_state.hpp"
#include "profile.hpp"
#include "sdbusplus.hpp"
#include "utils/flight_recorder.hpp"
#include "zone.hpp"

#include <systemd/sd-bus.h>

#include <nlohmann/json.hpp>
#include <sdbusplus/bus.hpp>
#include <sdbusplus/server/manager.hpp>
#include <sdeventplus/event.hpp>
#include <sdeventplus/utility/timer.hpp>

#include <algorithm>
#include <chrono>
#include <filesystem>
#include <functional>
#include <map>
#include <memory>
#include <tuple>
#include <utility>
#include <vector>

namespace phosphor::fan::control::json
{

using json = nlohmann::json;

std::vector<std::string> Manager::_activeProfiles;
std::map<std::string,
         std::map<std::string, std::pair<bool, std::vector<std::string>>>>
    Manager::_servTree;
std::map<std::string,
         std::map<std::string, std::map<std::string, PropertyVariantType>>>
    Manager::_objects;
std::unordered_map<std::string, PropertyVariantType> Manager::_parameters;
std::unordered_map<std::string, TriggerActions> Manager::_parameterTriggers;

const std::string Manager::dumpFile = "/tmp/fan_control_dump.json";

Manager::Manager(const sdeventplus::Event& event) :
    _bus(util::SDBusPlus::getBus()), _event(event),
    _mgr(util::SDBusPlus::getBus(), CONTROL_OBJPATH), _loadAllowed(true),
    _powerState(std::make_unique<PGoodState>(
        util::SDBusPlus::getBus(),
        std::bind(std::mem_fn(&Manager::powerStateChanged), this,
                  std::placeholders::_1)))
{}

void Manager::sighupHandler(sdeventplus::source::Signal&,
                            const struct signalfd_siginfo*)
{
    FlightRecorder::instance().log("main", "SIGHUP received");
    // Save current set of available and active profiles
    std::map<configKey, std::unique_ptr<Profile>> profiles;
    profiles.swap(_profiles);
    std::vector<std::string> activeProfiles;
    activeProfiles.swap(_activeProfiles);

    try
    {
        _loadAllowed = true;
        load();
    }
    catch (const std::runtime_error& re)
    {
        // Restore saved available and active profiles
        _loadAllowed = false;
        _profiles.swap(profiles);
        _activeProfiles.swap(activeProfiles);
        log<level::ERR>("Error reloading configs, no changes made",
                        entry("LOAD_ERROR=%s", re.what()));
        FlightRecorder::instance().log(
            "main", std::format("Error reloading configs, no changes made: {}",
                                re.what()));
    }
}

void Manager::dumpDebugData(sdeventplus::source::Signal&,
                            const struct signalfd_siginfo*)
{
    json data;
    FlightRecorder::instance().dump(data);
    dumpCache(data);

    std::for_each(_zones.begin(), _zones.end(), [&data](const auto& zone) {
        data["zones"][zone.second->getName()] = zone.second->dump();
    });

    std::ofstream file{Manager::dumpFile};
    if (!file)
    {
        log<level::ERR>("Could not open file for fan dump");
        return;
    }

    file << std::setw(4) << data;
}

void Manager::dumpCache(json& data)
{
    auto& objects = data["objects"];
    for (const auto& [path, interfaces] : _objects)
    {
        auto& interfaceJSON = objects[path];

        for (const auto& [interface, properties] : interfaces)
        {
            auto& propertyJSON = interfaceJSON[interface];
            for (const auto& [propName, propValue] : properties)
            {
                std::visit(
                    [&obj = propertyJSON[propName]](auto&& val) { obj = val; },
                    propValue);
            }
        }
    }

    auto& parameters = data["parameters"];
    for (const auto& [name, value] : _parameters)
    {
        std::visit([&obj = parameters[name]](auto&& val) { obj = val; }, value);
    }

    std::for_each(_events.begin(), _events.end(), [&data](const auto& event) {
        data["events"][event.second->getName()] = event.second->dump();
    });

    data["services"] = _servTree;
}

void Manager::load()
{
    if (_loadAllowed)
    {
        // Load the available profiles and which are active
        setProfiles();

        // Load the zone configurations
        auto zones = getConfig<Zone>(false, _event, this);
        // Load the fan configurations and move each fan into its zone
        auto fans = getConfig<Fan>(false);
        for (auto& fan : fans)
        {
            configKey fanProfile =
                std::make_pair(fan.second->getZone(), fan.first.second);
            auto itZone = std::find_if(
                zones.begin(), zones.end(), [&fanProfile](const auto& zone) {
                    return Manager::inConfig(fanProfile, zone.first);
                });
            if (itZone != zones.end())
            {
                if (itZone->second->getTarget() != fan.second->getTarget() &&
                    fan.second->getTarget() != 0)
                {
                    // Update zone target to current target of the fan in the
                    // zone
                    itZone->second->setTarget(fan.second->getTarget());
                }
                itZone->second->addFan(std::move(fan.second));
            }
        }

        // Save all currently available groups, if any, then clear for reloading
        auto groups = std::move(Event::getAllGroups(false));
        Event::clearAllGroups();

        std::map<configKey, std::unique_ptr<Event>> events;
        try
        {
            // Load any events configured, including all the groups
            events = getConfig<Event>(true, this, zones);
        }
        catch (const std::runtime_error& re)
        {
            // Restore saved set of all available groups for current events
            Event::setAllGroups(std::move(groups));
            throw re;
        }

        // Enable zones
        _zones = std::move(zones);
        std::for_each(_zones.begin(), _zones.end(),
                      [](const auto& entry) { entry.second->enable(); });

        // Clear current timers and signal subscriptions before enabling events
        // To save reloading services and/or objects into cache, do not clear
        // cache
        _timers.clear();
        _signals.clear();

        // Enable events
        _events = std::move(events);
        FlightRecorder::instance().log("main", "Enabling events");
        std::for_each(_events.begin(), _events.end(),
                      [](const auto& entry) { entry.second->enable(); });
        FlightRecorder::instance().log("main", "Done enabling events");

        _loadAllowed = false;
    }
}

void Manager::powerStateChanged(bool powerStateOn)
{
    if (powerStateOn)
    {
        FlightRecorder::instance().log("power", "Power on");
        if (_zones.empty())
        {
            throw std::runtime_error("No configured zones found at poweron");
        }
        std::for_each(_zones.begin(), _zones.end(), [](const auto& entry) {
            entry.second->setTarget(entry.second->getPoweronTarget());
        });

        // Tell events to run their power on triggers
        std::for_each(_events.begin(), _events.end(),
                      [](const auto& entry) { entry.second->powerOn(); });
    }
    else
    {
        FlightRecorder::instance().log("power", "Power off");
        // Tell events to run their power off triggers
        std::for_each(_events.begin(), _events.end(),
                      [](const auto& entry) { entry.second->powerOff(); });
    }
}

const std::vector<std::string>& Manager::getActiveProfiles()
{
    return _activeProfiles;
}

bool Manager::inConfig(const configKey& input, const configKey& comp)
{
    // Config names dont match, do not include in config
    if (input.first != comp.first)
    {
        return false;
    }
    // No profiles specified by input config, can be used in any config
    if (input.second.empty())
    {
        return true;
    }
    else
    {
        // Profiles must have one match in the other's profiles(and they must be
        // an active profile) to be used in the config
        return std::any_of(
            input.second.begin(), input.second.end(),
            [&comp](const auto& lProfile) {
                return std::any_of(
                    comp.second.begin(), comp.second.end(),
                    [&lProfile](const auto& rProfile) {
                        if (lProfile != rProfile)
                        {
                            return false;
                        }
                        auto activeProfs = getActiveProfiles();
                        return std::find(activeProfs.begin(), activeProfs.end(),
                                         lProfile) != activeProfs.end();
                    });
            });
    }
}

bool Manager::hasOwner(const std::string& path, const std::string& intf)
{
    auto itServ = _servTree.find(path);
    if (itServ == _servTree.end())
    {
        // Path not found in cache, therefore owner missing
        return false;
    }
    for (const auto& service : itServ->second)
    {
        auto itIntf = std::find_if(
            service.second.second.begin(), service.second.second.end(),
            [&intf](const auto& interface) { return intf == interface; });
        if (itIntf != std::end(service.second.second))
        {
            // Service found, return owner state
            return service.second.first;
        }
    }
    // Interface not found in cache, therefore owner missing
    return false;
}

void Manager::setOwner(const std::string& serv, bool hasOwner)
{
    // Update owner state on all entries of `serv`
    for (auto& itPath : _servTree)
    {
        auto itServ = itPath.second.find(serv);
        if (itServ != itPath.second.end())
        {
            itServ->second.first = hasOwner;

            // Remove associated interfaces from object cache when service no
            // longer has an owner
            if (!hasOwner && _objects.find(itPath.first) != _objects.end())
            {
                for (auto& intf : itServ->second.second)
                {
                    _objects[itPath.first].erase(intf);
                }
            }
        }
    }
}

void Manager::setOwner(const std::string& path, const std::string& serv,
                       const std::string& intf, bool isOwned)
{
    // Set owner state for specific object given
    auto& ownIntf = _servTree[path][serv];
    ownIntf.first = isOwned;
    auto itIntf = std::find_if(
        ownIntf.second.begin(), ownIntf.second.end(),
        [&intf](const auto& interface) { return intf == interface; });
    if (itIntf == std::end(ownIntf.second))
    {
        ownIntf.second.emplace_back(intf);
    }

    // Update owner state on all entries of the same `serv` & `intf`
    for (auto& itPath : _servTree)
    {
        if (itPath.first == path)
        {
            // Already set/updated owner on this path for `serv` & `intf`
            continue;
        }
        for (auto& itServ : itPath.second)
        {
            if (itServ.first != serv)
            {
                continue;
            }
            auto itIntf = std::find_if(
                itServ.second.second.begin(), itServ.second.second.end(),
                [&intf](const auto& interface) { return intf == interface; });
            if (itIntf != std::end(itServ.second.second))
            {
                itServ.second.first = isOwned;
            }
        }
    }
}

const std::string& Manager::findService(const std::string& path,
                                        const std::string& intf)
{
    static const std::string empty = "";

    auto itServ = _servTree.find(path);
    if (itServ != _servTree.end())
    {
        for (const auto& service : itServ->second)
        {
            auto itIntf = std::find_if(
                service.second.second.begin(), service.second.second.end(),
                [&intf](const auto& interface) { return intf == interface; });
            if (itIntf != std::end(service.second.second))
            {
                // Service found, return service name
                return service.first;
            }
        }
    }

    return empty;
}

void Manager::addServices(const std::string& intf, int32_t depth)
{
    // Get all subtree objects for the given interface
    auto objects = util::SDBusPlus::getSubTreeRaw(util::SDBusPlus::getBus(),
                                                  "/", intf, depth);
    // Add what's returned to the cache of path->services
    for (auto& itPath : objects)
    {
        auto pathIter = _servTree.find(itPath.first);
        if (pathIter != _servTree.end())
        {
            // Path found in cache
            for (auto& itServ : itPath.second)
            {
                auto servIter = pathIter->second.find(itServ.first);
                if (servIter != pathIter->second.end())
                {
                    if (std::find(servIter->second.second.begin(),
                                  servIter->second.second.end(), intf) ==
                        servIter->second.second.end())
                    {
                        // Add interface to cache
                        servIter->second.second.emplace_back(intf);
                    }
                }
                else
                {
                    // Service not found in cache
                    auto intfs = {intf};
                    pathIter->second[itServ.first] =
                        std::make_pair(true, intfs);
                }
            }
        }
        else
        {
            // Path not found in cache
            auto intfs = {intf};
            for (const auto& [servName, servIntfs] : itPath.second)
            {
                _servTree[itPath.first][servName] = std::make_pair(true, intfs);
            }
        }
    }
}

const std::string& Manager::getService(const std::string& path,
                                       const std::string& intf)
{
    // Retrieve service from cache
    const auto& serviceName = findService(path, intf);
    if (serviceName.empty())
    {
        addServices(intf, 0);
        return findService(path, intf);
    }

    return serviceName;
}

std::vector<std::string>
    Manager::findPaths(const std::string& serv, const std::string& intf)
{
    std::vector<std::string> paths;

    for (const auto& path : _servTree)
    {
        auto itServ = path.second.find(serv);
        if (itServ != path.second.end())
        {
            if (std::find(itServ->second.second.begin(),
                          itServ->second.second.end(), intf) !=
                itServ->second.second.end())
            {
                if (std::find(paths.begin(), paths.end(), path.first) ==
                    paths.end())
                {
                    paths.push_back(path.first);
                }
            }
        }
    }

    return paths;
}

std::vector<std::string> Manager::getPaths(const std::string& serv,
                                           const std::string& intf)
{
    auto paths = findPaths(serv, intf);
    if (paths.empty())
    {
        addServices(intf, 0);
        return findPaths(serv, intf);
    }

    return paths;
}

void Manager::insertFilteredObjects(ManagedObjects& ref)
{
    // Filter out objects that aren't part of a group
    const auto& allGroupMembers = Group::getAllMembers();
    auto it = ref.begin();

    while (it != ref.end())
    {
        if (allGroupMembers.find(it->first) == allGroupMembers.end())
        {
            it = ref.erase(it);
        }
        else
        {
            it++;
        }
    }

    for (auto& [path, pathMap] : ref)
    {
        for (auto& [intf, intfMap] : pathMap)
        {
            // for each property on this path+interface
            for (auto& [prop, value] : intfMap)
            {
                setProperty(path, intf, prop, value);
            }
        }
    }
}

void Manager::addObjects(const std::string& path, const std::string& intf,
                         const std::string& prop,
                         const std::string& serviceName)
{
    auto service = serviceName;
    if (service.empty())
    {
        service = getService(path, intf);
        if (service.empty())
        {
            // Log service not found for object
            log<level::DEBUG>(
                std::format(
                    "Unable to get service name for path {}, interface {}",
                    path, intf)
                    .c_str());
            return;
        }
    }
    else
    {
        // The service is known, so the service cache can be
        // populated even if the path itself isn't present.
        const auto& s = findService(path, intf);
        if (s.empty())
        {
            addServices(intf, 0);
        }
    }

    auto objMgrPaths = getPaths(service, "org.freedesktop.DBus.ObjectManager");

    bool useManagedObj = false;

    if (!objMgrPaths.empty())
    {
        for (const auto& objMgrPath : objMgrPaths)
        {
            // Get all managed objects of service
            auto objects =
                util::SDBusPlus::getManagedObjects<PropertyVariantType>(
                    _bus, service, objMgrPath);
            if (objects.size() > 0)
            {
                useManagedObj = true;
            }
            // insert all objects that are in groups but remove any NaN values
            insertFilteredObjects(objects);
        }
    }

    if (!useManagedObj)
    {
        // No object manager interface provided by service?
        // Or no object is managed?
        // Attempt to retrieve property directly
        try
        {
            auto value =
                util::SDBusPlus::getPropertyVariant<PropertyVariantType>(
                    _bus, service, path, intf, prop);

            setProperty(path, intf, prop, value);
        }
        catch (const std::exception& e)
        {}
        return;
    }
}

const std::optional<PropertyVariantType> Manager::getProperty(
    const std::string& path, const std::string& intf, const std::string& prop)
{
    // TODO Objects hosted by fan control (i.e. ThermalMode) are required to
    // update the cache upon being set/updated
    auto itPath = _objects.find(path);
    if (itPath != _objects.end())
    {
        auto itIntf = itPath->second.find(intf);
        if (itIntf != itPath->second.end())
        {
            auto itProp = itIntf->second.find(prop);
            if (itProp != itIntf->second.end())
            {
                return itProp->second;
            }
        }
    }

    return std::nullopt;
}

void Manager::setProperty(const std::string& path, const std::string& intf,
                          const std::string& prop, PropertyVariantType value)
{
    // filter NaNs out of the cache
    if (PropertyContainsNan(value))
    {
        // dont use operator [] if paths dont exist
        if (_objects.find(path) != _objects.end() &&
            _objects[path].find(intf) != _objects[path].end())
        {
            _objects[path][intf].erase(prop);
        }
    }
    else
    {
        _objects[path][intf][prop] = std::move(value);
    }
}

void Manager::addTimer(const TimerType type,
                       const std::chrono::microseconds interval,
                       std::unique_ptr<TimerPkg> pkg)
{
    auto dataPtr =
        std::make_unique<TimerData>(std::make_pair(type, std::move(*pkg)));
    Timer timer(_event,
                std::bind(&Manager::timerExpired, this, std::ref(*dataPtr)));
    if (type == TimerType::repeating)
    {
        timer.restart(interval);
    }
    else if (type == TimerType::oneshot)
    {
        timer.restartOnce(interval);
    }
    else
    {
        throw std::invalid_argument("Invalid Timer Type");
    }
    _timers.emplace_back(std::move(dataPtr), std::move(timer));
}

void Manager::addGroups(const std::vector<Group>& groups)
{
    std::string lastServ;
    std::vector<std::string> objMgrPaths;
    std::set<std::string> services;
    for (const auto& group : groups)
    {
        for (const auto& member : group.getMembers())
        {
            try
            {
                auto service = group.getService();
                if (service.empty())
                {
                    service = getService(member, group.getInterface());
                }

                if (!service.empty())
                {
                    if (lastServ != service)
                    {
                        objMgrPaths = getPaths(
                            service, "org.freedesktop.DBus.ObjectManager");
                        lastServ = service;
                    }

                    // Look for the ObjectManager as an ancestor from the
                    // member.
                    auto hasObjMgr = std::any_of(
                        objMgrPaths.begin(), objMgrPaths.end(),
                        [&member](const auto& path) {
                            return member.find(path) != std::string::npos;
                        });

                    if (!hasObjMgr)
                    {
                        // No object manager interface provided for group member
                        // Attempt to retrieve group member property directly
                        try
                        {
                            auto value = util::SDBusPlus::getPropertyVariant<
                                PropertyVariantType>(_bus, service, member,
                                                     group.getInterface(),
                                                     group.getProperty());
                            setProperty(member, group.getInterface(),
                                        group.getProperty(), value);
                        }
                        catch (const std::exception& e)
                        {}
                        continue;
                    }

                    if (services.find(service) == services.end())
                    {
                        services.insert(service);
                        for (const auto& objMgrPath : objMgrPaths)
                        {
                            // Get all managed objects from the service
                            auto objects = util::SDBusPlus::getManagedObjects<
                                PropertyVariantType>(_bus, service, objMgrPath);

                            // Insert objects into cache
                            insertFilteredObjects(objects);
                        }
                    }
                }
            }
            catch (const util::DBusError&)
            {
                // No service or property found for group member with the
                // group's configured interface
                continue;
            }
        }
    }
}

void Manager::timerExpired(TimerData& data)
{
    if (std::get<bool>(data.second))
    {
        addGroups(std::get<const std::vector<Group>&>(data.second));
    }

    auto& actions =
        std::get<std::vector<std::unique_ptr<ActionBase>>&>(data.second);
    // Perform the actions in the timer data
    std::for_each(actions.begin(), actions.end(),
                  [](auto& action) { action->run(); });

    // Remove oneshot timers after they expired
    if (data.first == TimerType::oneshot)
    {
        auto itTimer = std::find_if(
            _timers.begin(), _timers.end(), [&data](const auto& timer) {
                return (data.first == timer.first->first &&
                        (std::get<std::string>(data.second) ==
                         std::get<std::string>(timer.first->second)));
            });
        if (itTimer != std::end(_timers))
        {
            _timers.erase(itTimer);
        }
    }
}

void Manager::handleSignal(sdbusplus::message_t& msg,
                           const std::vector<SignalPkg>* pkgs)
{
    for (auto& pkg : *pkgs)
    {
        // Handle the signal callback and only run the actions if the handler
        // updated the cache for the given SignalObject
        if (std::get<SignalHandler>(
                pkg)(msg, std::get<SignalObject>(pkg), *this))
        {
            // Perform the actions in the handler package
            auto& actions = std::get<TriggerActions>(pkg);
            std::for_each(actions.begin(), actions.end(), [](auto& action) {
                if (action.get())
                {
                    action.get()->run();
                }
            });
        }
        // Only rewind message when not last package
        if (&pkg != &pkgs->back())
        {
            sd_bus_message_rewind(msg.get(), true);
        }
    }
}

void Manager::setProfiles()
{
    // Profiles JSON config file is optional
    auto confFile =
        fan::JsonConfig::getConfFile(confAppName, Profile::confFileName, true);

    _profiles.clear();
    if (!confFile.empty())
    {
        for (const auto& entry : fan::JsonConfig::load(confFile))
        {
            auto obj = std::make_unique<Profile>(entry);
            _profiles.emplace(
                std::make_pair(obj->getName(), obj->getProfiles()),
                std::move(obj));
        }
    }

    // Ensure all configurations use the same set of active profiles
    // (In case a profile's active state changes during configuration)
    _activeProfiles.clear();
    for (const auto& profile : _profiles)
    {
        if (profile.second->isActive())
        {
            _activeProfiles.emplace_back(profile.first.first);
        }
    }
}

void Manager::addParameterTrigger(
    const std::string& name, std::vector<std::unique_ptr<ActionBase>>& actions)
{
    auto it = _parameterTriggers.find(name);
    if (it != _parameterTriggers.end())
    {
        std::for_each(actions.begin(), actions.end(),
                      [&actList = it->second](auto& action) {
                          actList.emplace_back(std::ref(action));
                      });
    }
    else
    {
        TriggerActions triggerActions;
        std::for_each(actions.begin(), actions.end(),
                      [&triggerActions](auto& action) {
                          triggerActions.emplace_back(std::ref(action));
                      });
        _parameterTriggers[name] = std::move(triggerActions);
    }
}

void Manager::runParameterActions(const std::string& name)
{
    auto it = _parameterTriggers.find(name);
    if (it != _parameterTriggers.end())
    {
        std::for_each(it->second.begin(), it->second.end(),
                      [](auto& action) { action.get()->run(); });
    }
}

} // namespace phosphor::fan::control::json
