//
// Created by Dan Crosby on 4/18/22.
//

#include <fstream>
#include <iostream>
#include <memory>
#include <string>
#include <vector>

#include "MapInfoCalculator.hpp"
#include "src/main/cpp/net/eagle0/common/FilesystemUtils.hpp"
#include "src/main/cpp/net/eagle0/shardok/library/settings/GameSettings.hpp"
#include "src/main/cpp/net/eagle0/shardok/util/BattalionTypeRegistrar.hpp"
#include "src/main/cpp/net/eagle0/shardok/util/MapLoader.hpp"

auto main(const int argc, char** argv) -> int {
    FilesystemUtils::SetExecPath(argv[0]);

    std::ostream* outputStreamPtr = &std::cout;
    std::ofstream outputFile{};
    if (argc > 1) {
        const std::string outputPath = argv[1];
        outputFile.open(outputPath);
        outputStreamPtr = &outputFile;
    }
    std::ostream& outputStream = *outputStreamPtr;

    const auto gameSettings = std::make_shared<shardok::GameSettings>();
    auto setter = gameSettings->GetSetter();
    shardok::BattalionTypeRegistrar::RegisterBattalionTypes(setter);
    const shardok::BattalionTypeSPtr& battalionType = gameSettings->GetGetter().GetBattalionType(
            net::eagle0::shardok::storage::fb::BattalionTypeId_LIGHT_INFANTRY);

    const std::vector<std::string> mapNames = GetMapNames();
    std::vector<OneMapInfo> mapInfos{};
    mapInfos.reserve(mapNames.size());
    for (const std::string& mapName : mapNames) {
        std::shared_ptr<shardok::ActionPointDistancesCache> apdCache =
                std::make_shared<shardok::ActionPointDistancesCache>();

        mapInfos.push_back(CalculateMap(mapName, apdCache, battalionType));
    }

    outputStream << "[";
    bool firstMap = true;
    for (const OneMapInfo& mapInfo : mapInfos) {
        if (firstMap) {
            outputStream << '\n';
            firstMap = false;
        } else {
            outputStream << "," << '\n';
        }
        outputStream << "  {" << '\n';
        outputStream << R"(    "name": ")" << mapInfo.name << "\"," << '\n';

        outputStream << "    \"castleCount\": " << mapInfo.castleCount << "," << '\n';
        outputStream << "    \"positions\": {";

        bool firstPosition = true;
        for (const auto& [position, count] : mapInfo.positionsRequiringCrossing) {
            if (firstPosition) {
                outputStream << '\n';
                firstPosition = false;
            } else {
                outputStream << "," << '\n';
            }

            outputStream << "      \"" << position << "\": " << count;
        }
        outputStream << '\n' << "    }" << '\n' << "  }";
    }
    outputStream << '\n' << "]" << '\n';
}
