#include "activation_static.hpp"

#include "item_updater.hpp"

#include <phosphor-logging/log.hpp>

namespace openpower
{
namespace software
{
namespace updater
{
namespace softwareServer = sdbusplus::xyz::openbmc_project::Software::server;

using namespace phosphor::logging;

auto ActivationStatic::activation(Activations value) -> Activations
{
    auto ret = value;
    if (value != softwareServer::Activation::Activations::Active)
    {
        redundancyPriority.reset(nullptr);
    }

    if (value == softwareServer::Activation::Activations::Activating)
    {
        fs::path imagePath(IMG_DIR);
        imagePath /= versionId;

        for (const auto& entry : fs::directory_iterator(imagePath))
        {
            if (entry.path().extension() == ".pnor")
            {
                pnorFilePath = entry;
                break;
            }
        }
        if (pnorFilePath.empty())
        {
            log<level::ERR>("Unable to find pnor file",
                            entry("DIR=%s", imagePath.c_str()));
            ret = softwareServer::Activation::Activations::Failed;
            goto out;
        }
#ifdef WANT_SIGNATURE_VERIFY
        // Validate the signed image.
        if (!validateSignature(pnorFilePath.filename()))
        {
            // Cleanup
            activationBlocksTransition.reset(nullptr);
            activationProgress.reset(nullptr);

            ret = softwareServer::Activation::Activations::Failed;
            goto out;
        }
#endif
        if (parent.freeSpace())
        {
            startActivation();
        }
        else
        {
            ret = softwareServer::Activation::Activations::Failed;
        }
    }
    else
    {
        activationBlocksTransition.reset(nullptr);
        activationProgress.reset(nullptr);
    }

out:
    return softwareServer::Activation::activation(ret);
}

void ActivationStatic::startActivation()
{
    if (!activationProgress)
    {
        activationProgress = std::make_unique<ActivationProgress>(bus, path);
    }

    if (!activationBlocksTransition)
    {
        activationBlocksTransition =
            std::make_unique<ActivationBlocksTransition>(bus, path);
    }

    // TODO: check why the signal is still received without calling this
    // function?
    subscribeToSystemdSignals();

    log<level::INFO>("Start programming...",
                     entry("PNOR=%s", pnorFilePath.c_str()));

    std::string pnorFileEscaped = pnorFilePath.string();
    // Escape all '/' to '-'
    std::replace(pnorFileEscaped.begin(), pnorFileEscaped.end(), '/', '-');

    constexpr auto updatePNORService = "openpower-pnor-update@";
    pnorUpdateUnit = std::string(updatePNORService) + pnorFileEscaped +
                     ".service";
    auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
                                      SYSTEMD_INTERFACE, "StartUnit");
    method.append(pnorUpdateUnit, "replace");
    bus.call_noreply(method);

    activationProgress->progress(10);
}

void ActivationStatic::unitStateChange(sdbusplus::message_t& msg)
{
    uint32_t newStateID{};
    sdbusplus::message::object_path newStateObjPath;
    std::string newStateUnit{};
    std::string newStateResult{};

    // Read the msg and populate each variable
    msg.read(newStateID, newStateObjPath, newStateUnit, newStateResult);

    if (newStateUnit == pnorUpdateUnit)
    {
        if (newStateResult == "done")
        {
            finishActivation();
        }
        if (newStateResult == "failed" || newStateResult == "dependency")
        {
            Activation::activation(
                softwareServer::Activation::Activations::Failed);
        }
    }
}

void ActivationStatic::finishActivation()
{
    activationProgress->progress(90);

    // Set Redundancy Priority before setting to Active
    if (!redundancyPriority)
    {
        redundancyPriority = std::make_unique<RedundancyPriority>(bus, path,
                                                                  *this, 0);
    }

    activationProgress->progress(100);

    activationBlocksTransition.reset();
    activationProgress.reset();

    unsubscribeFromSystemdSignals();
    // Remove version object from image manager
    deleteImageManagerObject();
    // Create active association
    parent.createActiveAssociation(path);
    // Create updateable association as this
    // can be re-programmed.
    parent.createUpdateableAssociation(path);
    // Create functional association
    parent.updateFunctionalAssociation(versionId);

    Activation::activation(Activation::Activations::Active);
}

} // namespace updater
} // namespace software
} // namespace openpower
