#include <AssetManager/AssetManager.hpp>
#include <Encyclopedia/Encyclopedia.hpp>
#include <ItemUsageRegistry/ItemUsageRegistry.hpp>
#include <WorldMigrator/WorldMigrator.hpp>
#include <cstdlib>
#include <filesystem>
#include <csignal>
#include <VoxelverseSession/VoxelverseSession.hpp>
#include <GraphicsContext/GraphicsContext.hpp>
#include <Display/PreloaderDisplay/PreloaderDisplay.hpp>
#include <Utilities/Utilities.hpp>
#include <BlockRegistry/BlockRegistry.hpp>
#include <ItemRegistry/ItemRegistry.hpp>
#include <Server/Server.hpp>
#include <Utilities/Socket.hpp>
#include <EntityRegistry/EntityRegistry.hpp>
#include <ControllerRegistry/ControllerRegistry.hpp>
#include <ItemRecipeRegistry/ItemRecipeRegistry.hpp>
#include <FuelRuleRegistry/FuelRuleRegistry.hpp>
#include <SmeltingRuleRegistry/SmeltingRuleRegistry.hpp>
#include <FluidRegistry/FluidRegistry.hpp>
#include <Settings/Settings.hpp>
#include <Utilities/Async.hpp>
#include <Machine/MChemicalReactor/MChemicalReactor.hpp>
#include <MaceratorRuleRegistry/MaceratorRuleRegistry.hpp>
#include <AudioManager/AudioManager.hpp>
#include <Version/Version.hpp>
#include <Utilities/ServerInit.hpp>
#include <Utilities/ServerSessionTable.hpp>
#include <WorldTypeRegistry/WorldTypeRegistry.hpp>
#include <WorldComponentRegistry/WorldComponentRegistry.hpp>
#include <DecorationRegistry/DecorationRegistry.hpp>
#include <MilestoneRegistry/MilestoneRegistry.hpp>
#include <PlayerTriggerRegistry/PlayerTriggerRegistry.hpp>

#ifdef _WIN32
#   define GLOBAL_VAR __declspec(dllexport)
#else
#   define GLOBAL_VAR
#endif

GLOBAL_VAR std::unique_ptr<VoxelverseSession> voxelverse;

#undef GLOBAL_VAR

int VoxelverseSession::start(int argc, char **argv)
{
    startTime = std::chrono::steady_clock::now();
    
    for (int i=0; i<argc; i++)
    {
        args.push_back(argv[i]);
    }

#ifdef SIGPIPE
    signal(SIGPIPE, SIG_IGN);
#endif
    Log::init(formatString("voxelverse-$+.log", getSessionTypeName()));
    Log::info(formatString("Build version: $+", Version::ofThisBuild));

    if (getenv("VOXELVERSE_DUMP_TERRAIN_NOISE") != nullptr)
    {
        std::filesystem::create_directories("dumps");
        envVars.dumpTerrainNoise = true;
    }

    envVars.devMode = getenv("VOXELVERSE_DEV") != nullptr;

    assets.init();
    settings.init();
    initAsync();
    fluidRegistry.registerAllFluids();
    blockRegistry.registerAllBlocks();
    itemRegistry.registerAllItems();
    entityRegistry.registerAllEntities();
    controllerRegistry.registerAllControllers();
    itemRecipeRegistry.registerAllRecipes();
    fuelRuleRegistry.registerAllRules();
    smeltingRuleRegistry.registerAllRules();
    MChemicalReactor::initRecipes();
    maceratorRuleRegistry.registerAllRules();
    worldTypeRegistry.registerAllWorldTypes();
    worldComponentRegistry.registerAllComponents();
    milestoneRegistry.registerAllMilestones();
    playerTriggerRegistry.registerAllTriggers();
    itemUsageRegistry.init();
    encyclopedia.init();
    WorldMigrator::initMigrations();

#ifdef _WIN32
    WSADATA wsaData;
    int wsaResult = WSAStartup(MAKEWORD(2,2), &wsaData);

    if (wsaResult != 0)
    {
        crash(formatString("Failed to initialize WinSock: error $+", wsaResult));
    }
#endif

    int status = run();

    itemRecipeRegistry.shutdown();
    maceratorRuleRegistry.shutdown();
    smeltingRuleRegistry.shutdown();
    fuelRuleRegistry.shutdown();

    Log::flush();

    return status;
}