/**
 * 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 "extensions/openpower-pels/manager.hpp"
#include "log_manager.hpp"
#include "pel_utils.hpp"

#include <fstream>
#include <regex>
#include <xyz/openbmc_project/Common/error.hpp>

#include <gtest/gtest.h>

using namespace openpower::pels;
namespace fs = std::filesystem;

class ManagerTest : public CleanPELFiles
{
  public:
    ManagerTest() : logManager(bus, "logging_path")
    {
        sd_event_default(&sdEvent);
        bus.attach_event(sdEvent, SD_EVENT_PRIORITY_NORMAL);
    }

    ~ManagerTest()
    {
        sd_event_unref(sdEvent);
    }

    sdbusplus::bus::bus bus = sdbusplus::bus::new_default();
    phosphor::logging::internal::Manager logManager;
    sd_event* sdEvent;
};

fs::path makeTempDir()
{
    char path[] = "/tmp/tempnameXXXXXX";
    std::filesystem::path dir = mkdtemp(path);
    return dir;
}

std::optional<fs::path> findAnyPELInRepo()
{
    // PELs are named <timestamp>_<ID>
    std::regex expr{"\\d+_\\d+"};

    for (auto& f : fs::directory_iterator(getPELRepoPath() / "logs"))
    {
        if (std::regex_search(f.path().string(), expr))
        {
            return f.path();
        }
    }
    return std::nullopt;
}

// Test that using the RAWPEL=<file> with the Manager::create() call gets
// a PEL saved in the repository.
TEST_F(ManagerTest, TestCreateWithPEL)
{
    std::unique_ptr<DataInterfaceBase> dataIface =
        std::make_unique<DataInterface>(bus);

    openpower::pels::Manager manager{logManager, std::move(dataIface)};

    // Create a PEL, write it to a file, and pass that filename into
    // the create function.
    auto data = pelDataFactory(TestPELType::pelSimple);

    fs::path pelFilename = makeTempDir() / "rawpel";
    std::ofstream pelFile{pelFilename};
    pelFile.write(reinterpret_cast<const char*>(data.data()), data.size());
    pelFile.close();

    std::string adItem = "RAWPEL=" + pelFilename.string();
    std::vector<std::string> additionalData{adItem};
    std::vector<std::string> associations;

    manager.create("error message", 42, 0,
                   phosphor::logging::Entry::Level::Error, additionalData,
                   associations);

    // Find the file in the PEL repository directory
    auto pelPathInRepo = findAnyPELInRepo();

    EXPECT_TRUE(pelPathInRepo);

    // Now remove it based on its OpenBMC event log ID
    manager.erase(42);

    pelPathInRepo = findAnyPELInRepo();

    EXPECT_FALSE(pelPathInRepo);

    fs::remove_all(pelFilename.parent_path());
}

// Test that the message registry can be used to build a PEL.
TEST_F(ManagerTest, TestCreateWithMessageRegistry)
{
    const auto registry = R"(
{
    "PELs":
    [
        {
            "Name": "xyz.openbmc_project.Error.Test",
            "Subsystem": "power_supply",
            "ActionFlags": ["service_action", "report"],
            "SRC":
            {
                "ReasonCode": "0x2030"
            },
            "Documentation":
            {
                "Description": "A PGOOD Fault",
                "Message": "PS had a PGOOD Fault"
            }
        }
    ]
}
)";

    auto path = getMessageRegistryPath();
    fs::create_directories(path);
    path /= "message_registry.json";

    std::ofstream registryFile{path};
    registryFile << registry;
    registryFile.close();

    auto bus = sdbusplus::bus::new_default();
    phosphor::logging::internal::Manager logManager(bus, "logging_path");

    std::unique_ptr<DataInterfaceBase> dataIface =
        std::make_unique<DataInterface>(logManager.getBus());

    openpower::pels::Manager manager{logManager, std::move(dataIface)};

    std::vector<std::string> additionalData;
    std::vector<std::string> associations;

    // Create the event log to create the PEL from.
    manager.create("xyz.openbmc_project.Error.Test", 33, 0,
                   phosphor::logging::Entry::Level::Error, additionalData,
                   associations);

    // Ensure a PEL was created in the repository
    auto pelFile = findAnyPELInRepo();
    ASSERT_TRUE(pelFile);

    auto data = readPELFile(*pelFile);
    PEL pel(*data);

    // Spot check it.  Other testcases cover the details.
    EXPECT_TRUE(pel.valid());
    EXPECT_EQ(pel.obmcLogID(), 33);
    EXPECT_EQ(pel.primarySRC().value()->asciiString(),
              "BD612030                        ");

    // Remove it
    manager.erase(33);
    pelFile = findAnyPELInRepo();
    EXPECT_FALSE(pelFile);

    // Create an event log that can't be found in the registry.
    manager.create("xyz.openbmc_project.Error.Foo", 33, 0,
                   phosphor::logging::Entry::Level::Error, additionalData,
                   associations);

    // Currently, no PEL should be created.  Eventually, a 'missing registry
    // entry' PEL will be there.
    pelFile = findAnyPELInRepo();
    EXPECT_FALSE(pelFile);
}

TEST_F(ManagerTest, TestDBusMethods)
{
    std::unique_ptr<DataInterfaceBase> dataIface =
        std::make_unique<DataInterface>(bus);

    Manager manager{logManager, std::move(dataIface)};

    // Create a PEL, write it to a file, and pass that filename into
    // the create function so there's one in the repo.
    auto data = pelDataFactory(TestPELType::pelSimple);

    fs::path pelFilename = makeTempDir() / "rawpel";
    std::ofstream pelFile{pelFilename};
    pelFile.write(reinterpret_cast<const char*>(data.data()), data.size());
    pelFile.close();

    std::string adItem = "RAWPEL=" + pelFilename.string();
    std::vector<std::string> additionalData{adItem};
    std::vector<std::string> associations;

    manager.create("error message", 42, 0,
                   phosphor::logging::Entry::Level::Error, additionalData,
                   associations);

    // getPELFromOBMCID
    auto newData = manager.getPELFromOBMCID(42);
    EXPECT_EQ(newData.size(), data.size());

    // Read the PEL to get the ID for later
    PEL pel{newData};
    auto id = pel.id();

    EXPECT_THROW(
        manager.getPELFromOBMCID(id + 1),
        sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);

    // getPEL
    auto unixfd = manager.getPEL(id);

    // Get the size
    struct stat s;
    int r = fstat(unixfd, &s);
    ASSERT_EQ(r, 0);
    auto size = s.st_size;

    // Open the FD and check the contents
    FILE* fp = fdopen(unixfd, "r");
    ASSERT_NE(fp, nullptr);

    std::vector<uint8_t> fdData;
    fdData.resize(size);
    r = fread(fdData.data(), 1, size, fp);
    EXPECT_EQ(r, size);

    EXPECT_EQ(newData, fdData);

    fclose(fp);

    EXPECT_THROW(
        manager.getPEL(id + 1),
        sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);

    // hostAck
    manager.hostAck(id);

    EXPECT_THROW(
        manager.hostAck(id + 1),
        sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);

    // hostReject
    manager.hostReject(id, Manager::RejectionReason::BadPEL);
    manager.hostReject(id, Manager::RejectionReason::HostFull);

    EXPECT_THROW(
        manager.hostReject(id + 1, Manager::RejectionReason::BadPEL),
        sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);

    fs::remove_all(pelFilename.parent_path());
}
