/**
 * Copyright © 2019 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 "updater.hpp"

#include "aei_updater.hpp"
#include "pmbus.hpp"
#include "types.hpp"
#include "utility.hpp"
#include "utils.hpp"
#include "validator.hpp"
#include "version.hpp"

#include <phosphor-logging/lg2.hpp>
#include <xyz/openbmc_project/Logging/Create/client.hpp>

#include <chrono>
#include <fstream>
#include <iostream>
#include <map>
#include <string>

namespace util = phosphor::power::util;

namespace updater
{

namespace internal
{

// Define the CRC-8 polynomial (CRC-8-CCITT)
constexpr uint8_t CRC8_POLYNOMIAL = 0x07;
constexpr uint8_t CRC8_INITIAL = 0x00;

// Get the appropriate Updater class instance based PSU model number
std::unique_ptr<updater::Updater> getClassInstance(
    const std::string& model, const std::string& psuInventoryPath,
    const std::string& devPath, const std::string& imageDir)
{
    if (model == "51E9" || model == "51DA")
    {
        return std::make_unique<aeiUpdater::AeiUpdater>(psuInventoryPath,
                                                        devPath, imageDir);
    }
    return std::make_unique<Updater>(psuInventoryPath, devPath, imageDir);
}

// Function to locate FW file with model and extension bin or hex
const std::string getFWFilenamePath(const std::string& directory)
{
    namespace fs = std::filesystem;
    // Get the last part of the directory name (model number)
    std::string model = fs::path(directory).filename().string();
    for (const auto& entry : fs::directory_iterator(directory))
    {
        if (entry.is_regular_file())
        {
            std::string filename = entry.path().filename().string();

            if ((filename.rfind(model, 0) == 0) && (filename.ends_with(".bin")))
            {
                return directory + "/" + filename;
            }
        }
    }
    return "";
}

// Compute CRC-8 checksum for a vector of bytes
uint8_t calculateCRC8(const std::vector<uint8_t>& data)
{
    uint8_t crc = CRC8_INITIAL;

    for (const auto& byte : data)
    {
        crc ^= byte;
        for (int i = 0; i < 8; ++i)
        {
            if (crc & 0x80)
                crc = (crc << 1) ^ CRC8_POLYNOMIAL;
            else
                crc <<= 1;
        }
    }
    return crc;
}

// Delay execution for a specified number of milliseconds
void delay(const int& milliseconds)
{
    std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds));
}

// Convert big endian (32 bit integer) to a vector of little endian.
std::vector<uint8_t> bigEndianToLittleEndian(const uint32_t bigEndianValue)
{
    std::vector<uint8_t> littleEndianBytes(4);

    littleEndianBytes[3] = (bigEndianValue >> 24) & 0xFF;
    littleEndianBytes[2] = (bigEndianValue >> 16) & 0xFF;
    littleEndianBytes[1] = (bigEndianValue >> 8) & 0xFF;
    littleEndianBytes[0] = bigEndianValue & 0xFF;
    return littleEndianBytes;
}

// Validate the existence and size of a firmware file.
bool validateFWFile(const std::string& fileName)
{
    // Ensure the file exists and get the file size.
    if (!std::filesystem::exists(fileName))
    {
        lg2::error("Firmware file not found: {FILE}", "FILE", fileName);
        return false;
    }

    // Check the file size
    auto fileSize = std::filesystem::file_size(fileName);
    if (fileSize == 0)
    {
        lg2::error("Firmware {FILE} is empty", "FILE", fileName);
        return false;
    }
    return true;
}

// Open a firmware file for reading in binary mode.
std::unique_ptr<std::ifstream> openFirmwareFile(const std::string& fileName)
{
    if (fileName.empty())
    {
        lg2::error("Firmware file path is not provided");
        return nullptr;
    }
    auto inputFile =
        std::make_unique<std::ifstream>(fileName, std::ios::binary);
    if (!inputFile->is_open())
    {
        lg2::error("Failed to open firmware file: {FILE}", "FILE", fileName);
        return nullptr;
    }
    return inputFile;
}

// Read firmware bytes from input stream.
std::vector<uint8_t> readFirmwareBytes(std::ifstream& inputFile,
                                       const size_t numberOfBytesToRead)
{
    std::vector<uint8_t> readDataBytes(numberOfBytesToRead, 0xFF);
    try
    {
        // Enable exceptions for failbit and badbit
        inputFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
        inputFile.read(reinterpret_cast<char*>(readDataBytes.data()),
                       numberOfBytesToRead);
        size_t bytesRead = inputFile.gcount();
        if (bytesRead != numberOfBytesToRead)
        {
            readDataBytes.resize(bytesRead);
        }
    }
    catch (const std::ios_base::failure& e)
    {
        lg2::error("Error reading firmware: {ERROR}", "ERROR", e);
        readDataBytes.clear();
    }
    return readDataBytes;
}

} // namespace internal

bool update(sdbusplus::bus_t& bus, const std::string& psuInventoryPath,
            const std::string& imageDir)
{
    auto devPath = utils::getDevicePath(bus, psuInventoryPath);

    if (devPath.empty())
    {
        return false;
    }

    std::filesystem::path fsPath(imageDir);

    std::unique_ptr<updater::Updater> updaterPtr = internal::getClassInstance(
        fsPath.filename().string(), psuInventoryPath, devPath, imageDir);

    if (!updaterPtr->isReadyToUpdate())
    {
        lg2::error("PSU not ready to update PSU = {PATH}", "PATH",
                   psuInventoryPath);
        return false;
    }

    updaterPtr->bindUnbind(false);
    updaterPtr->createI2CDevice();
    int ret = updaterPtr->doUpdate();
    updaterPtr->bindUnbind(true);
    return ret == 0;
}

bool validateAndUpdate(sdbusplus::bus_t& bus,
                       const std::string& psuInventoryPath,
                       const std::string& imageDir)
{
    auto poweredOn = phosphor::power::util::isPoweredOn(bus, true);
    validator::PSUUpdateValidator psuValidator(bus, psuInventoryPath);
    if (!poweredOn && psuValidator.validToUpdate())
    {
        return updater::update(bus, psuInventoryPath, imageDir);
    }
    else
    {
        return false;
    }
}

Updater::Updater(const std::string& psuInventoryPath,
                 const std::string& devPath, const std::string& imageDir) :
    bus(sdbusplus::bus::new_default()), psuInventoryPath(psuInventoryPath),
    devPath(devPath), devName(utils::getDeviceName(devPath)), imageDir(imageDir)
{
    fs::path p = fs::path(devPath) / "driver";
    try
    {
        driverPath =
            fs::canonical(p); // Get the path that points to the driver dir
    }
    catch (const fs::filesystem_error& e)
    {
        lg2::error("Failed to get canonical path DEVPATH= {PATH}, ERROR= {ERR}",
                   "PATH", devPath, "ERR", e);
    }
}

// During PSU update, it needs to access the PSU i2c device directly, so it
// needs to unbind the driver during the update, and re-bind after it's done.
// After unbind, the hwmon sysfs will be gone, and the psu-monitor will report
// errors. So set the PSU inventory's Present property to false so that
// psu-monitor will not report any errors.
void Updater::bindUnbind(bool doBind)
{
    if (!doBind)
    {
        // Set non-present before unbind the driver
        setPresent(doBind);
    }
    auto p = driverPath;
    p /= doBind ? "bind" : "unbind";
    std::ofstream out(p.string());
    out << devName;
    if (doBind)
    {
        internal::delay(500);
    }
    out.close();

    if (doBind)
    {
        // Set to present after bind the driver
        setPresent(doBind);
    }
}

void Updater::setPresent(bool present)
{
    try
    {
        auto service = util::getService(psuInventoryPath, INVENTORY_IFACE, bus);
        util::setProperty(INVENTORY_IFACE, PRESENT_PROP, psuInventoryPath,
                          service, bus, present);
    }
    catch (const std::exception& e)
    {
        lg2::error(
            "Failed to set present property PSU= {PATH}, PRESENT= {PRESENT}",
            "PATH", psuInventoryPath, "PRESENT", present);
    }
}

bool Updater::isReadyToUpdate()
{
    using namespace phosphor::pmbus;

    // Pre-condition for updating PSU:
    // * Host is powered off
    // * At least one other PSU is present
    // * All other PSUs that are present are having AC input and DC standby
    //   output

    if (util::isPoweredOn(bus, true))
    {
        lg2::warning("Unable to update PSU when host is on");
        return false;
    }

    bool hasOtherPresent = false;
    auto paths = util::getPSUInventoryPaths(bus);
    for (const auto& p : paths)
    {
        if (p == psuInventoryPath)
        {
            // Skip check for itself
            continue;
        }

        // Check PSU present
        bool present = false;
        try
        {
            auto service = util::getService(p, INVENTORY_IFACE, bus);
            util::getProperty(INVENTORY_IFACE, PRESENT_PROP, psuInventoryPath,
                              service, bus, present);
        }
        catch (const std::exception& e)
        {
            lg2::error("Failed to get present property PSU={PSU}", "PSU", p);
        }
        if (!present)
        {
            lg2::warning("PSU not present PSU={PSU}", "PSU", p);
            continue;
        }
        hasOtherPresent = true;

        // Typically the driver is still bound here, so it is possible to
        // directly read the debugfs to get the status.
        try
        {
            auto path = utils::getDevicePath(bus, p);
            PMBus pmbus(path);
            uint16_t statusWord = pmbus.read(STATUS_WORD, Type::Debug);
            auto status0Vout = pmbus.insertPageNum(STATUS_VOUT, 0);
            uint8_t voutStatus = pmbus.read(status0Vout, Type::Debug);
            if ((statusWord & status_word::VOUT_FAULT) ||
                (statusWord & status_word::INPUT_FAULT_WARN) ||
                (statusWord & status_word::VIN_UV_FAULT) ||
                // For ibm-cffps PSUs, the MFR (0x80)'s OV (bit 2) and VAUX
                // (bit 6) fault map to OV_FAULT, and UV (bit 3) fault maps to
                // UV_FAULT in vout status.
                (voutStatus & status_vout::UV_FAULT) ||
                (voutStatus & status_vout::OV_FAULT))
            {
                lg2::warning(
                    "Unable to update PSU when other PSU has input/ouput fault PSU={PSU}, STATUS_WORD={STATUS}, VOUT_BYTE={VOUT}",
                    "PSU", p, "STATUS", lg2::hex, statusWord, "VOUT", lg2::hex,
                    voutStatus);
                return false;
            }
        }
        catch (const std::exception& ex)
        {
            // If error occurs on accessing the debugfs, it means something went
            // wrong, e.g. PSU is not present, and it's not ready to update.
            lg2::error("{EX}", "EX", ex.what());
            return false;
        }
    }
    return hasOtherPresent;
}

int Updater::doUpdate()
{
    using namespace std::chrono;

    uint8_t data;
    uint8_t unlockData[12] = {0x45, 0x43, 0x44, 0x31, 0x36, 0x30,
                              0x33, 0x30, 0x30, 0x30, 0x34, 0x01};
    uint8_t bootFlag = 0x01;
    static_assert(sizeof(unlockData) == 12);

    i2c->write(0xf0, sizeof(unlockData), unlockData);
    printf("Unlock PSU\n");

    std::this_thread::sleep_for(milliseconds(5));

    i2c->write(0xf1, bootFlag);
    printf("Set boot flag ret\n");

    std::this_thread::sleep_for(seconds(3));

    i2c->read(0xf1, data);
    printf("Read of 0x%02x, 0x%02x\n", 0xf1, data);
    return 0;
}

void Updater::createI2CDevice()
{
    auto [id, addr] = utils::parseDeviceName(devName);
    i2c = i2c::create(id, addr);
}

void Updater::createServiceableEventLog(
    const std::string& errorName, const std::string& severity,
    std::map<std::string, std::string>& additionalData)
{
    if (!isEventLogEnabled() || isEventLoggedThisSession())
    {
        return;
    }

    using namespace sdbusplus::xyz::openbmc_project;
    using LoggingCreate =
        sdbusplus::client::xyz::openbmc_project::logging::Create<>;
    enableEventLoggedThisSession();
    try
    {
        additionalData["_PID"] = std::to_string(getpid());
        auto method = bus.new_method_call(LoggingCreate::default_service,
                                          LoggingCreate::instance_path,
                                          LoggingCreate::interface, "Create");
        method.append(errorName, severity, additionalData);

        bus.call(method);
    }
    catch (const sdbusplus::exception::SdBusError& e)
    {
        lg2::error(
            "Failed creating event log for fault {ERROR_NAME}, error {ERR}",
            "ERROR_NAME", errorName, "ERR", e);
    }
    disableEventLogging();
}

std::map<std::string, std::string> Updater::getI2CAdditionalData()
{
    std::map<std::string, std::string> additionalData;
    auto [id, addr] = utils::parseDeviceName(getDevName());
    std::string hexIdString = std::format("0x{:x}", id);
    std::string hexAddrString = std::format("0x{:x}", addr);

    additionalData["CALLOUT_IIC_BUS"] = hexIdString;
    additionalData["CALLOUT_IIC_ADDR"] = hexAddrString;
    return additionalData;
}

/*
 * callOutI2CEventLog calls out FRUs in the following order:
 * 1 - PSU  high priority
 * 2 - CALLOUT_IIC_BUS
 */
void Updater::callOutI2CEventLog(
    std::map<std::string, std::string> extraAdditionalData,
    const std::string& exceptionString, const int errorCode)
{
    std::map<std::string, std::string> additionalData = {
        {"CALLOUT_INVENTORY_PATH", getPsuInventoryPath()}};
    additionalData.merge(extraAdditionalData);
    additionalData.merge(getI2CAdditionalData());
    additionalData["CALLOUT_ERRNO"] = std::to_string(errorCode);
    if (!exceptionString.empty())
    {
        additionalData["I2C_EXCEPTION"] = exceptionString;
    }
    createServiceableEventLog(FW_UPDATE_FAILED_MSG, ERROR_SEVERITY,
                              additionalData);
}

/*
 * callOutPsuEventLog calls out PSU and system planar
 */
void Updater::callOutPsuEventLog(
    std::map<std::string, std::string> extraAdditionalData)
{
    std::map<std::string, std::string> additionalData = {
        {"CALLOUT_INVENTORY_PATH", getPsuInventoryPath()}};
    additionalData.merge(extraAdditionalData);
    createServiceableEventLog(updater::FW_UPDATE_FAILED_MSG,
                              updater::ERROR_SEVERITY, additionalData);
}

/*
 * callOutSWEventLog calls out the BMC0001 procedure.
 */
void Updater::callOutSWEventLog(
    std::map<std::string, std::string> additionalData)
{
    createServiceableEventLog(updater::PSU_FW_FILE_ISSUE_MSG,
                              updater::ERROR_SEVERITY, additionalData);
}

/*
 * callOutGoodEventLog calls out a successful firmware update.
 */
void Updater::callOutGoodEventLog()
{
    std::map<std::string, std::string> additionalData = {
        {"SUCCESSFUL_PSU_UPDATE", getPsuInventoryPath()},
        {"FIRMWARE_VERSION", version::getVersion(bus, getPsuInventoryPath())}};
    createServiceableEventLog(updater::FW_UPDATE_SUCCESS_MSG,
                              updater::INFORMATIONAL_SEVERITY, additionalData);
}
} // namespace updater
