#include "ConfigLoader.h"

#include <optional>
#include <string>
#include <utility>

#include "toml.hpp"

#include "TomlHelpers.h"

BuildingsConfig ConfigLoader::loadBuildings(const std::string& path)
{
    const std::string file = "buildings.toml";
    toml::table tbl = utility::parseFile(path, file);

    BuildingsConfig cfg;
    const toml::array& arr = utility::requireArray(tbl["building"], file, "building");

    for (std::size_t i = 0; i < arr.size(); ++i)
    {
        const std::string elemPath = "building[" + std::to_string(i) + "]";
        const toml::table* bt = arr[i].as_table();
        if (bt == nullptr)
        {
            throw utility::makeError(file, elemPath, "not a table");
        }
        toml::table& mt = const_cast<toml::table&>(*bt);

        BuildingDef def;
        def.id                      = utility::requireString(mt["id"],                        file, elemPath + ".id");
        def.cost                    = static_cast<int>(utility::requireInt(mt["cost"],        file, elemPath + ".cost"));
        def.playerPlaceable         = utility::requireBool(mt["player_placeable"],            file, elemPath + ".player_placeable");
        def.constructionTimeSeconds = utility::requireDouble(mt["construction_time_seconds"], file, elemPath + ".construction_time_seconds");
        def.surfaceMask             = utility::requireStringArray(mt["surface_mask"],         file, elemPath + ".surface_mask");

        if (mt.contains("output_buffer_capacity"))
        {
            def.outputBufferCapacity = static_cast<int>(
                utility::requireInt(mt["output_buffer_capacity"], file, elemPath + ".output_buffer_capacity"));
        }

        if (mt.contains("tooltip"))
        {
            def.tooltip = utility::requireString(mt["tooltip"], file, elemPath + ".tooltip");
        }

        const std::optional<BuildingType> parsedType = parseBuildingType(def.id);
        if (!parsedType)
        {
            throw utility::makeError(file, elemPath + ".id", "unknown building id '" + def.id + "'");
        }
        def.type = *parsedType;

        cfg.buildings.push_back(std::move(def));
    }

    return cfg;
}
