#include "editor_impl.hpp"
#include "ipz_parser.hpp"

#include <nlohmann/json.hpp>

#include <algorithm>
#include <vector>

#include <gtest/gtest.h>

using namespace openpower::vpd;
using namespace openpower::vpd::manager::editor;
using namespace openpower::vpd::inventory;
using namespace openpower::vpd::constants;

class vpdManagerEditorTest : public ::testing::Test
{
  protected:
    Binary vpd;

    nlohmann::json jsonFile;

    // map to hold the mapping of location code and inventory path
    inventory::LocationCodeMap fruLocationCode;

  public:
    // constructor
    vpdManagerEditorTest()
    {
        processJson();
    }

    void processJson();
    void readFile(std::string pathToFile);
};

void vpdManagerEditorTest::readFile(std::string pathToFile)
{
    // read the json file and parse it
    std::ifstream vpdFile(pathToFile, std::ios::binary);

    if (!vpdFile)
    {
        throw std::runtime_error("json file not found");
    }

    vpd.assign((std::istreambuf_iterator<char>(vpdFile)),
               std::istreambuf_iterator<char>());
}

void vpdManagerEditorTest::processJson()
{
    // read the json file and parse it
    std::ifstream json("vpd-manager-test/vpd_editor_test.json",
                       std::ios::binary);

    if (!json)
    {
        throw std::runtime_error("json file not found");
    }

    jsonFile = nlohmann::json::parse(json);

    const nlohmann::json& groupFRUS =
        jsonFile["frus"].get_ref<const nlohmann::json::object_t&>();
    for (const auto& itemFRUS : groupFRUS.items())
    {
        const std::vector<nlohmann::json>& groupEEPROM =
            itemFRUS.value().get_ref<const nlohmann::json::array_t&>();
        for (const auto& itemEEPROM : groupEEPROM)
        {
            fruLocationCode.emplace(
                itemEEPROM["extraInterfaces"][IBM_LOCATION_CODE_INF]
                          ["LocationCode"]
                              .get_ref<const nlohmann::json::string_t&>(),
                itemEEPROM["inventoryPath"]
                    .get_ref<const nlohmann::json::string_t&>());
        }
    }
}

TEST_F(vpdManagerEditorTest, InvalidFile)
{
    Binary dataToUodate{'M', 'O', 'D', 'I', 'F', 'Y',
                        'D', 'A', 'T', 'A', 'O', 'K'};

    Binary emptyVpdFile;
    try
    {
        // Invalid kwd name
        EditorImpl edit("VINI", "SN", std::move(emptyVpdFile));
        edit.updateKeyword(dataToUodate, 0, true);
    }
    catch (const std::exception& e)
    {
        EXPECT_EQ(std::string(e.what()), std::string("Invalid File"));
    }
}

TEST_F(vpdManagerEditorTest, InvalidHeader)
{
    Binary dataToUodate{'M', 'O', 'D', 'I', 'F', 'Y',
                        'D', 'A', 'T', 'A', 'O', 'K'};

    readFile("vpd-manager-test/invalidHeaderFile.dat");
    try
    {
        // the path is dummy
        EditorImpl edit("VINI", "SN", std::move(vpd));
        edit.updateKeyword(dataToUodate, 0, true);
    }
    catch (const std::exception& e)
    {
        EXPECT_EQ(std::string(e.what()), std::string("VHDR record not found"));
    }
}

TEST_F(vpdManagerEditorTest, InvalidRecordName)
{
    Binary dataToUodate{'M', 'O', 'D', 'I', 'F', 'Y',
                        'D', 'A', 'T', 'A', 'O', 'K'};

    readFile("vpd-manager-test/vpdFile.dat");

    try
    {
        // Invalid record name "VIN", path is dummy
        EditorImpl edit("VIN", "SN", std::move(vpd));
        edit.updateKeyword(dataToUodate, 0, true);
    }
    catch (const std::exception& e)
    {
        EXPECT_EQ(std::string(e.what()), std::string("Record not found"));
    }
}

TEST_F(vpdManagerEditorTest, InvalidKWdName)
{
    Binary dataToUodate{'M', 'O', 'D', 'I', 'F', 'Y',
                        'D', 'A', 'T', 'A', 'O', 'K'};

    readFile("vpd-manager-test/vpdFile.dat");

    try
    {
        // All valid data
        EditorImpl edit("VINI", "Sn", std::move(vpd));
        edit.updateKeyword(dataToUodate, 0, true);
    }
    catch (const std::runtime_error& e)
    {
        EXPECT_EQ(std::string(e.what()), std::string("Keyword not found"));
    }
}

TEST_F(vpdManagerEditorTest, UpdateKwd_Success)
{
    Binary dataToUodate{'M', 'O', 'D', 'I', 'F', 'Y',
                        'D', 'A', 'T', 'A', 'O', 'K'};

    readFile("vpd-manager-test/vpdFile.dat");

    try
    {
        // All valid data, but can't update with dummy ECC code
        EditorImpl edit("VINI", "SN", std::move(vpd));
        edit.updateKeyword(dataToUodate, 0, true);
    }
    catch (const std::runtime_error& e)
    {
        EXPECT_EQ(std::string(e.what()), std::string("Ecc update failed"));
    }
}

int main(int argc, char** argv)
{
    ::testing::InitGoogleTest(&argc, argv);

    return RUN_ALL_TESTS();
}
