#include <game/gamemanager.hpp>
#include <algorithm>

namespace Game {
    GameStateEnum GameManager::mCurrentGameState = GameStateEnum::RUNNING;
    
    void GameManager::run(std::stop_token stopToken) {
        using namespace std::chrono_literals;
        LOG("GameManager slave thread started");
        Object::Camera::getInstance().setPosition(0.f, 0.f); // Start with camera at (0, 0)

        mLastUpdate = clock::now(); // Get the update

        while (!stopToken.stop_requested()) {
            if (mCurrentGameState == GameStateEnum::PAUSED) {
                std::this_thread::sleep_for(100ms);
                continue;
            }

            clock::time_point now = clock::now();
            std::chrono::duration<float> elapsedDt = now - mLastUpdate;
            float seconds = elapsedDt.count();

            const int updatesPerSecond = std::max(1, mTargetUpdatesPerSecond);
            const auto frameDuration = std::chrono::duration<double>(1.0 / static_cast<double>(updatesPerSecond));
            const auto frameStart = std::chrono::steady_clock::now();

            try {
                Input::update(); // Update input states at the start of each frame
                auto entities = State::GameState::getInstance().getEntitiesSnapshot();
                for (auto* entity : entities) {
                    if (!entity || !entity->isActive()) {
                        continue;
                    }

                    // Update components first
                    entity->updateComponents(seconds);

                    entity->update(seconds);
                }
            } catch (const std::exception& e) {
                ERROR("Exception in GameManager thread: " << e.what());
            }

            mLastDelta = seconds;
            mLastUpdate = now;

            #ifdef DEBUG
            GameManager::setSharedData("lastDelta", mLastDelta);
            #endif

            const auto elapsed = std::chrono::steady_clock::now() - frameStart;
            const auto remaining = frameDuration - elapsed;
            if (remaining > 0s) {
                std::this_thread::sleep_for(remaining);
            }
        }
    }

    // Statics
    std::unordered_map<std::string, std::string> GameManager::mSharedStrings;
    std::unordered_map<std::string, int> GameManager::mSharedInts;
    std::unordered_map<std::string, float> GameManager::mSharedFloats;
    std::unordered_map<std::string, bool> GameManager::mSharedBools;

    void GameManager::removeSharedData(const std::string& key, SharedDataType type) {
        if (type == SharedDataType::STRING) {
            mSharedStrings.erase(key);
        } else if (type == SharedDataType::INT) {
            mSharedInts.erase(key);
        } else if (type == SharedDataType::FLOAT) {
            mSharedFloats.erase(key);
        } else if (type == SharedDataType::BOOL) {
            mSharedBools.erase(key);
        }
    }
    
}