/**
 * Copyright © 2017 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 "argument.hpp"
#include "watchdog.hpp"

#include <iostream>
#include <optional>
#include <phosphor-logging/elog-errors.hpp>
#include <phosphor-logging/elog.hpp>
#include <phosphor-logging/log.hpp>
#include <string>
#include <xyz/openbmc_project/Common/error.hpp>

using phosphor::watchdog::ArgumentParser;
using phosphor::watchdog::Watchdog;
using sdbusplus::xyz::openbmc_project::State::server::convertForMessage;

static void exitWithError(const char* err, char** argv)
{
    ArgumentParser::usage(argv);
    std::cerr << "ERROR: " << err << "\n";
    exit(EXIT_FAILURE);
}

void printActionTargetMap(const Watchdog::ActionTargetMap& actionTargetMap)
{
    std::cerr << "Action Targets:\n";
    for (const auto& [action, target] : actionTargetMap)
    {
        std::cerr << "  " << convertForMessage(action) << " -> " << target
                  << "\n";
    }
    std::cerr << std::flush;
}

int main(int argc, char* argv[])
{
    using namespace phosphor::logging;
    using InternalFailure =
        sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
    // Read arguments.
    auto options = ArgumentParser(argc, argv);

    // Parse out continue argument.
    auto continueParam = (options)["continue"];
    // Default it to exit on watchdog timeout
    auto continueAfterTimeout = false;
    if (!continueParam.empty())
    {
        continueAfterTimeout = true;
    }

    // Parse out path argument.
    auto pathParam = (options)["path"];
    if (pathParam.empty())
    {
        exitWithError("Path not specified.", argv);
    }
    if (pathParam.size() > 1)
    {
        exitWithError("Multiple paths specified.", argv);
    }
    auto path = pathParam.back();

    // Parse out service name argument
    auto serviceParam = (options)["service"];
    if (serviceParam.empty())
    {
        exitWithError("Service not specified.", argv);
    }
    if (serviceParam.size() > 1)
    {
        exitWithError("Multiple services specified.", argv);
    }
    auto service = serviceParam.back();

    // Parse out target argument. It is fine if the caller does not
    // pass this if they are not interested in calling into any target
    // on meeting a condition.
    auto targetParam = (options)["target"];
    if (targetParam.size() > 1)
    {
        exitWithError("Multiple targets specified.", argv);
    }
    Watchdog::ActionTargetMap actionTargetMap;
    if (!targetParam.empty())
    {
        auto target = targetParam.back();
        actionTargetMap[Watchdog::Action::HardReset] = target;
        actionTargetMap[Watchdog::Action::PowerOff] = target;
        actionTargetMap[Watchdog::Action::PowerCycle] = target;
    }

    // Parse out the action_target arguments. We allow one target to map
    // to an action. These targets can replace the target specified above.
    for (const auto& actionTarget : (options)["action_target"])
    {
        size_t keyValueSplit = actionTarget.find("=");
        if (keyValueSplit == std::string::npos)
        {
            exitWithError(
                "Invalid action_target format, expect <action>=<target>.",
                argv);
        }

        std::string key = actionTarget.substr(0, keyValueSplit);
        std::string value = actionTarget.substr(keyValueSplit + 1);

        // Convert an action from a fully namespaced value
        Watchdog::Action action;
        try
        {
            action = Watchdog::convertActionFromString(key);
        }
        catch (const sdbusplus::exception::InvalidEnumString&)
        {
            exitWithError("Bad action specified.", argv);
        }

        // Detect duplicate action target arguments
        if (actionTargetMap.find(action) != actionTargetMap.end())
        {
            exitWithError("Duplicate action specified", argv);
        }

        actionTargetMap[action] = std::move(value);
    }
    printActionTargetMap(actionTargetMap);

    // Parse out the fallback settings for the watchdog. Note that we require
    // both of the fallback arguments to do anything here, but having a fallback
    // is entirely optional.
    auto fallbackActionParam = (options)["fallback_action"];
    auto fallbackIntervalParam = (options)["fallback_interval"];
    if (fallbackActionParam.empty() ^ fallbackIntervalParam.empty())
    {
        exitWithError("Only one of the fallback options was specified.", argv);
    }
    if (fallbackActionParam.size() > 1 || fallbackIntervalParam.size() > 1)
    {
        exitWithError("Multiple fallbacks specified.", argv);
    }
    std::optional<Watchdog::Fallback> fallback;
    if (!fallbackActionParam.empty())
    {
        Watchdog::Action action;
        try
        {
            action =
                Watchdog::convertActionFromString(fallbackActionParam.back());
        }
        catch (const sdbusplus::exception::InvalidEnumString&)
        {
            exitWithError("Bad action specified.", argv);
        }
        uint64_t interval;
        try
        {
            interval = std::stoull(fallbackIntervalParam.back());
        }
        catch (const std::logic_error&)
        {
            exitWithError("Failed to convert fallback interval to integer.",
                          argv);
        }
        fallback = Watchdog::Fallback{
            .action = action,
            .interval = interval,
            .always = false,
        };
    }

    auto fallbackAlwaysParam = (options)["fallback_always"];
    if (!fallbackAlwaysParam.empty())
    {
        if (!fallback)
        {
            exitWithError("Specified the fallback should always be enabled but "
                          "no fallback provided.",
                          argv);
        }
        fallback->always = true;
    }

    sd_event* event = nullptr;
    auto r = sd_event_default(&event);
    if (r < 0)
    {
        log<level::ERR>("Error creating a default sd_event handler");
        return r;
    }
    phosphor::watchdog::EventPtr eventP{event};
    event = nullptr;

    // Get a handle to system dbus.
    auto bus = sdbusplus::bus::new_default();

    // Add systemd object manager.
    sdbusplus::server::manager::manager(bus, path.c_str());

    // Attach the bus to sd_event to service user requests
    bus.attach_event(eventP.get(), SD_EVENT_PRIORITY_NORMAL);

    try
    {
        // Create a watchdog object
        Watchdog watchdog(bus, path.c_str(), eventP, std::move(actionTargetMap),
                          std::move(fallback));

        // Claim the bus
        bus.request_name(service.c_str());

        // Loop until our timer expires and we don't want to continue
        while (continueAfterTimeout || !watchdog.timerExpired())
        {
            // -1 denotes wait for ever
            r = sd_event_run(eventP.get(), (uint64_t)-1);
            if (r < 0)
            {
                log<level::ERR>("Error waiting for events");
                elog<InternalFailure>();
            }
        }
    }
    catch (InternalFailure& e)
    {
        phosphor::logging::commit<InternalFailure>();

        // Need a coredump in the error cases.
        std::terminate();
    }
    return 0;
}
