#include "watchdog_service.hpp"

#include <ipmid/api.h>

#include <exception>
#include <phosphor-logging/elog-errors.hpp>
#include <phosphor-logging/elog.hpp>
#include <phosphor-logging/log.hpp>
#include <sdbusplus/bus.hpp>
#include <sdbusplus/message.hpp>
#include <stdexcept>
#include <string>
#include <xyz/openbmc_project/Common/error.hpp>
#include <xyz/openbmc_project/State/Watchdog/server.hpp>

using phosphor::logging::elog;
using phosphor::logging::entry;
using phosphor::logging::level;
using phosphor::logging::log;
using sdbusplus::message::variant_ns::get;
using sdbusplus::message::variant_ns::variant;
using sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
using sdbusplus::xyz::openbmc_project::State::server::convertForMessage;
using sdbusplus::xyz::openbmc_project::State::server::Watchdog;

static constexpr char wd_path[] = "/xyz/openbmc_project/watchdog/host0";
static constexpr char wd_intf[] = "xyz.openbmc_project.State.Watchdog";
static constexpr char prop_intf[] = "org.freedesktop.DBus.Properties";

ipmi::ServiceCache WatchdogService::wd_service(wd_intf, wd_path);

WatchdogService::WatchdogService() : bus(ipmid_get_sd_bus_connection())
{
}

void WatchdogService::resetTimeRemaining(bool enableWatchdog)
{
    bool wasValid = wd_service.isValid(bus);
    auto request = wd_service.newMethodCall(bus, wd_intf, "ResetTimeRemaining");
    request.append(enableWatchdog);
    auto response = bus.call(request);
    if (response.is_method_error())
    {
        wd_service.invalidate();
        if (wasValid)
        {
            // Retry the request once in case the cached service was stale
            return resetTimeRemaining(enableWatchdog);
        }
        log<level::ERR>(
            "WatchdogService: Method error resetting time remaining",
            entry("ENABLE_WATCHDOG=%d", !!enableWatchdog));
        elog<InternalFailure>();
    }
}

WatchdogService::Properties WatchdogService::getProperties()
{
    bool wasValid = wd_service.isValid(bus);
    auto request = wd_service.newMethodCall(bus, prop_intf, "GetAll");
    request.append(wd_intf);
    auto response = bus.call(request);
    if (response.is_method_error())
    {
        wd_service.invalidate();
        if (wasValid)
        {
            // Retry the request once in case the cached service was stale
            return getProperties();
        }
        log<level::ERR>("WatchdogService: Method error getting properties");
        elog<InternalFailure>();
    }
    try
    {
        std::map<std::string, variant<bool, uint64_t, std::string>> properties;
        response.read(properties);
        Properties wd_prop;
        wd_prop.initialized = get<bool>(properties.at("Initialized"));
        wd_prop.enabled = get<bool>(properties.at("Enabled"));
        wd_prop.expireAction = Watchdog::convertActionFromString(
            get<std::string>(properties.at("ExpireAction")));
        wd_prop.interval = get<uint64_t>(properties.at("Interval"));
        wd_prop.timeRemaining = get<uint64_t>(properties.at("TimeRemaining"));
        return wd_prop;
    }
    catch (const std::exception& e)
    {
        log<level::ERR>("WatchdogService: Decode error in get properties",
                        entry("ERROR=%s", e.what()),
                        entry("REPLY_SIG=%s", response.get_signature()));
        elog<InternalFailure>();
    }

    // Needed instead of elog<InternalFailure>() since the compiler can't
    // deduce the that elog<>() always throws
    throw std::runtime_error(
        "WatchdogService: Should not reach end of getProperties");
}

template <typename T>
T WatchdogService::getProperty(const std::string& key)
{
    bool wasValid = wd_service.isValid(bus);
    auto request = wd_service.newMethodCall(bus, prop_intf, "Get");
    request.append(wd_intf, key);
    auto response = bus.call(request);
    if (response.is_method_error())
    {
        wd_service.invalidate();
        if (wasValid)
        {
            // Retry the request once in case the cached service was stale
            return getProperty<T>(key);
        }
        log<level::ERR>("WatchdogService: Method error getting property",
                        entry("PROPERTY=%s", key.c_str()));
        elog<InternalFailure>();
    }
    try
    {
        variant<T> value;
        response.read(value);
        return get<T>(value);
    }
    catch (const std::exception& e)
    {
        log<level::ERR>("WatchdogService: Decode error in get property",
                        entry("PROPERTY=%s", key.c_str()),
                        entry("ERROR=%s", e.what()),
                        entry("REPLY_SIG=%s", response.get_signature()));
        elog<InternalFailure>();
    }

    // Needed instead of elog<InternalFailure>() since the compiler can't
    // deduce the that elog<>() always throws
    throw std::runtime_error(
        "WatchdogService: Should not reach end of getProperty");
}

template <typename T>
void WatchdogService::setProperty(const std::string& key, const T& val)
{
    bool wasValid = wd_service.isValid(bus);
    auto request = wd_service.newMethodCall(bus, prop_intf, "Set");
    request.append(wd_intf, key, variant<T>(val));
    auto response = bus.call(request);
    if (response.is_method_error())
    {
        wd_service.invalidate();
        if (wasValid)
        {
            // Retry the request once in case the cached service was stale
            return setProperty(key, val);
        }
        log<level::ERR>("WatchdogService: Method error setting property",
                        entry("PROPERTY=%s", key.c_str()));
        elog<InternalFailure>();
    }
}

bool WatchdogService::getInitialized()
{
    return getProperty<bool>("Initialized");
}

void WatchdogService::setInitialized(bool initialized)
{
    setProperty("Initialized", initialized);
}

void WatchdogService::setEnabled(bool enabled)
{
    setProperty("Enabled", enabled);
}

void WatchdogService::setExpireAction(Action expireAction)
{
    setProperty("ExpireAction", convertForMessage(expireAction));
}

void WatchdogService::setInterval(uint64_t interval)
{
    setProperty("Interval", interval);
}

void WatchdogService::setTimeRemaining(uint64_t timeRemaining)
{
    setProperty("TimeRemaining", timeRemaining);
}
