#include "config.h"

#include "activation.hpp"

#include "utils.hpp"

#include <phosphor-logging/elog-errors.hpp>
#include <phosphor-logging/lg2.hpp>

#include <exception>
#include <filesystem>
#include <format>
#include <stdexcept>
#include <vector>

namespace phosphor
{
namespace software
{
namespace updater
{

constexpr auto SYSTEMD_BUSNAME = "org.freedesktop.systemd1";
constexpr auto SYSTEMD_PATH = "/org/freedesktop/systemd1";
constexpr auto SYSTEMD_INTERFACE = "org.freedesktop.systemd1.Manager";

namespace fs = std::filesystem;
namespace softwareServer = sdbusplus::xyz::openbmc_project::Software::server;

using namespace phosphor::logging;
using SoftwareActivation = softwareServer::Activation;

auto Activation::activation(Activations value) -> Activations
{
    if (value == Status::Activating)
    {
        value = startActivation();
    }
    else
    {
        activationBlocksTransition.reset();
        activationProgress.reset();
    }

    return SoftwareActivation::activation(value);
}

auto Activation::requestedActivation(RequestedActivations value)
    -> RequestedActivations
{
    if ((value == SoftwareActivation::RequestedActivations::Active) &&
        (SoftwareActivation::requestedActivation() !=
         SoftwareActivation::RequestedActivations::Active))
    {
        // PSU image could be activated even when it's in active,
        // e.g. in case a PSU is replaced and has a older image, it will be
        // updated with the running PSU image that is stored in BMC.
        if ((activation() == Status::Ready) ||
            (activation() == Status::Failed) || activation() == Status::Active)
        {
            activation(Status::Activating);
        }
    }
    return SoftwareActivation::requestedActivation(value);
}

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

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

        if (newStateUnit == psuUpdateUnit)
        {
            if (newStateResult == "done")
            {
                onUpdateDone();
            }
            if (newStateResult == "failed" || newStateResult == "dependency")
            {
                onUpdateFailed();
            }
        }
    }
    catch (const std::exception& e)
    {
        lg2::error("Unable to handle unit state change event: {ERROR}", "ERROR",
                   e);
    }
}

bool Activation::doUpdate(const std::string& psuInventoryPath)
{
    currentUpdatingPsu = psuInventoryPath;
    try
    {
        psuUpdateUnit = getUpdateService(currentUpdatingPsu);
        auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
                                          SYSTEMD_INTERFACE, "StartUnit");
        method.append(psuUpdateUnit, "replace");
        bus.call_noreply(method);
        return true;
    }
    catch (const std::exception& e)
    {
        lg2::error("Error starting update service for PSU {PSU}: {ERROR}",
                   "PSU", psuInventoryPath, "ERROR", e);
        onUpdateFailed();
        return false;
    }
}

bool Activation::doUpdate()
{
    // When the queue is empty, all updates are done
    if (psuQueue.empty())
    {
        finishActivation();
        return true;
    }

    // Do the update on a PSU
    const auto& psu = psuQueue.front();
    return doUpdate(psu);
}

void Activation::onUpdateDone()
{
    auto progress = activationProgress->progress() + progressStep;
    activationProgress->progress(progress);

    // Update the activation association
    auto assocs = associations();
    assocs.emplace_back(ACTIVATION_FWD_ASSOCIATION, ACTIVATION_REV_ASSOCIATION,
                        currentUpdatingPsu);
    associations(assocs);

    activationListener->onUpdateDone(versionId, currentUpdatingPsu);
    currentUpdatingPsu.clear();

    psuQueue.pop();
    doUpdate(); // Update the next psu
}

void Activation::onUpdateFailed()
{
    // TODO: report an event
    lg2::error("Failed to update PSU {PSU}", "PSU", psuQueue.front());
    std::queue<std::string>().swap(psuQueue); // Clear the queue
    activation(Status::Failed);
}

Activation::Status Activation::startActivation()
{
    // Check if the activation has file path
    if (path().empty())
    {
        lg2::warning(
            "No image for the activation, skipped version {VERSION_ID}",
            "VERSION_ID", versionId);
        return activation(); // Return the previous activation status
    }

    auto psuPaths = utils::getPSUInventoryPaths(bus);
    if (psuPaths.empty())
    {
        lg2::warning("No PSU inventory found");
        return Status::Failed;
    }

    for (const auto& p : psuPaths)
    {
        if (!isPresent(p))
        {
            continue;
        }
        if (isCompatible(p))
        {
            if (utils::isAssociated(p, associations()))
            {
                lg2::notice("PSU {PSU} is already running the image, skipping",
                            "PSU", p);
                continue;
            }
            psuQueue.push(p);
        }
        else
        {
            lg2::notice("PSU {PSU} is not compatible", "PSU", p);
        }
    }

    if (psuQueue.empty())
    {
        lg2::warning("No PSU compatible with the software");
        return activation(); // Return the previous activation status
    }

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

    // The progress to be increased for each successful update of PSU
    // E.g. in case we have 4 PSUs:
    //   1. Initial progress is 10
    //   2. Add 20 after each update is done, so we will see progress to be 30,
    //      50, 70, 90
    //   3. When all PSUs are updated, it will be 100 and the interface is
    //   removed.
    progressStep = 80 / psuQueue.size();
    if (doUpdate())
    {
        activationProgress->progress(10);
        return Status::Activating;
    }
    else
    {
        return Status::Failed;
    }
}

void Activation::finishActivation()
{
    storeImage();
    activationProgress->progress(100);

    deleteImageManagerObject();

    associationInterface->createActiveAssociation(objPath);
    associationInterface->addFunctionalAssociation(objPath);
    associationInterface->addUpdateableAssociation(objPath);

    // Reset RequestedActivations to none so that it could be activated in
    // future
    requestedActivation(SoftwareActivation::RequestedActivations::None);
    activation(Status::Active);
}

void Activation::deleteImageManagerObject()
{
    // Get the Delete object for <versionID> inside image_manager
    std::vector<std::string> services;
    constexpr auto deleteInterface = "xyz.openbmc_project.Object.Delete";
    try
    {
        services = utils::getServices(bus, objPath.c_str(), deleteInterface);
    }
    catch (const std::exception& e)
    {
        lg2::error(
            "Unable to find services to Delete object path {PATH}: {ERROR}",
            "PATH", objPath, "ERROR", e);
    }

    // We need to find the phosphor-version-software-manager's version service
    // to invoke the delete interface
    constexpr auto versionServiceStr = "xyz.openbmc_project.Software.Version";
    std::string versionService;
    for (const auto& service : services)
    {
        if (service.find(versionServiceStr) != std::string::npos)
        {
            versionService = service;
            break;
        }
    }
    if (versionService.empty())
    {
        // When updating a stored image, there is no version object created by
        // "xyz.openbmc_project.Software.Version" service, so skip it.
        return;
    }

    // Call the Delete object for <versionID> inside image_manager
    try
    {
        auto method = bus.new_method_call(
            versionService.c_str(), objPath.c_str(), deleteInterface, "Delete");
        bus.call(method);
    }
    catch (const std::exception& e)
    {
        lg2::error("Unable to Delete object path {PATH}: {ERROR}", "PATH",
                   objPath, "ERROR", e);
    }
}

bool Activation::isPresent(const std::string& psuInventoryPath)
{
    bool isPres{false};
    try
    {
        auto service =
            utils::getService(bus, psuInventoryPath.c_str(), ITEM_IFACE);
        isPres = utils::getProperty<bool>(bus, service.c_str(),
                                          psuInventoryPath.c_str(), ITEM_IFACE,
                                          PRESENT);
    }
    catch (const std::exception& e)
    {
        // Treat as a warning condition and assume the PSU is missing.  The
        // D-Bus information might not be available if the PSU is missing.
        lg2::warning("Unable to determine if PSU {PSU} is present: {ERROR}",
                     "PSU", psuInventoryPath, "ERROR", e);
    }
    return isPres;
}

bool Activation::isCompatible(const std::string& psuInventoryPath)
{
    bool isCompat{false};
    try
    {
        auto service =
            utils::getService(bus, psuInventoryPath.c_str(), ASSET_IFACE);
        auto psuManufacturer = utils::getProperty<std::string>(
            bus, service.c_str(), psuInventoryPath.c_str(), ASSET_IFACE,
            MANUFACTURER);
        auto psuModel = utils::getModel(psuInventoryPath);
        // The model shall match
        if (psuModel == model)
        {
            // If PSU inventory has manufacturer property, it shall match
            if (psuManufacturer.empty() || (psuManufacturer == manufacturer))
            {
                isCompat = true;
            }
        }
    }
    catch (const std::exception& e)
    {
        lg2::error(
            "Unable to determine if PSU {PSU} is compatible with firmware "
            "versionId {VERSION_ID}: {ERROR}",
            "PSU", psuInventoryPath, "VERSION_ID", versionId, "ERROR", e);
    }
    return isCompat;
}

void Activation::storeImage()
{
    // If image is not in IMG_DIR (temporary storage) then exit.  We don't want
    // to copy from IMG_DIR_PERSIST or IMG_DIR_BUILTIN.
    auto src = path();
    if (!src.starts_with(IMG_DIR))
    {
        return;
    }

    // Store image in persistent dir separated by model
    // and only store the latest one by removing old ones
    auto dst = fs::path(IMG_DIR_PERSIST) / model;
    try
    {
        fs::remove_all(dst);
        fs::create_directories(dst);
        fs::copy(src, dst);
        path(dst.string()); // Update the FilePath interface
    }
    catch (const fs::filesystem_error& e)
    {
        lg2::error("Error storing PSU image: src={SRC}, dst={DST}: {ERROR}",
                   "SRC", src, "DST", dst, "ERROR", e);
    }
}

std::string Activation::getUpdateService(const std::string& psuInventoryPath)
{
    fs::path imagePath(path());

    // The systemd unit shall be escaped
    std::string args = psuInventoryPath;
    args += "\\x20";
    args += imagePath;
    std::replace(args.begin(), args.end(), '/', '-');

    std::string service = PSU_UPDATE_SERVICE;
    auto p = service.find('@');
    if (p == std::string::npos)
    {
        throw std::runtime_error{std::format(
            "Invalid PSU update service name: {}", PSU_UPDATE_SERVICE)};
    }
    service.insert(p + 1, args);
    return service;
}

void ActivationBlocksTransition::enableRebootGuard()
{
    lg2::info("PSU image activating - BMC reboots are disabled.");

    auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
                                      SYSTEMD_INTERFACE, "StartUnit");
    method.append("reboot-guard-enable.service", "replace");
    bus.call_noreply_noerror(method);
}

void ActivationBlocksTransition::disableRebootGuard()
{
    lg2::info("PSU activation has ended - BMC reboots are re-enabled.");

    auto method = bus.new_method_call(SYSTEMD_BUSNAME, SYSTEMD_PATH,
                                      SYSTEMD_INTERFACE, "StartUnit");
    method.append("reboot-guard-disable.service", "replace");
    bus.call_noreply_noerror(method);
}

} // namespace updater
} // namespace software
} // namespace phosphor
