#include "Global.h"
#include "Input.h"
#include "Instance.h"
#include "Log.h"
#include "Setup.h"
#include "bx/bx.h"
#include "bx/timer.h"
#include "rendering/Rendering.h"

namespace Game
{
    class GameSetup
    {
      public:
        GameRendering Rendering;
    };

    namespace
    {
        GameSetup SetupInstance;
    }

    void Setup(SharedData& shared)
    {
        LOG("Game Setup Start!");

        if (shared.Game.PermanentStorage == nullptr)
        {
            LOG_ERROR("Game memory not initialized!!");
            return;
        }
        if (shared.Game.EntityStorage == nullptr)
        {
            LOG_ERROR("Entity memory not initialized!");
            return;
        }
        if (shared.Game.PermanentStorageSize < sizeof(GameInstance))
        {
            LOG_ERROR("Game memory too small! %u < %u", shared.Game.PermanentStorageSize, sizeof(GameInstance));
            return;
        }
        GameInstance& instance = *reinterpret_cast<GameInstance*>(shared.Game.PermanentStorage);
        if (sizeof(GameInstance) != instance.Size)
        {
            LOG_WARN("Game instance size changed, resetting!");
            instance = {};
        }
        instance.UsedScratchAmount = 0;
        SetShared(shared);
        SetInstance(instance);
        SetupInstance.Rendering.Setup();
        instance.GameLevel.Setup(shared.Game);
        instance.IsInitialized = true;
    }

    void Update()
    {
        auto& inst = GetInstance();
        int64_t newNowHP = bx::getHPCounter() - inst.Time.StartTime;
        inst.Time.DeltaHP = newNowHP - inst.Time.NowHP;
        inst.Time.NowHP = newNowHP;
        inst.Time.Now = (double)inst.Time.NowHP / bx::getHPFrequency();
        inst.Time.Delta = (double)inst.Time.DeltaHP / bx::getHPFrequency();
        GetShared().Window.PerfCounters[(int32_t)PerfCounterType::GameDelta].Write(inst.Time.DeltaHP,
                                                                                   GetShared().Window.FrameCounter);

        if (GetKeyPressedNow(ScanCode::R))
        {
            GetInstance().Size = 0;
            Shutdown();
            Setup(GetShared());
        }
        SetupInstance.Rendering.Update();

        auto& win = GetShared().Window;
        win.MouseDeltaX = 0.0f;
        win.MouseDeltaY = 0.0f;
        bx::memCopy(win.LastHeldScanCodes, win.HeldScanCodes, sizeof(win.HeldScanCodes));
        bx::memCopy(win.LastHeldMouseButtons, win.HeldMouseButtons, sizeof(win.HeldMouseButtons));
    }

    void Shutdown()
    {
        LOG("Shutdown");
        SetupInstance.Rendering.Shutdown();
    }
} // namespace Game
