#include "Deer/Application.h"
#include <functional>
#include <thread>

#ifdef DEER_RENDER
#include "DeerRender/Render/RenderCommand.h"
#include "DeerRender/Render/RenderUtils.h"
#include "DeerRender/Render/Render.h"

#include "DeerRender/ImGui/ImGuiLayer.h"
#include "imgui.h"
#endif

namespace Deer {
    namespace Application_tmp {
        Function tickCallback;
        bool running;

        const double targetUpdateTime = 1.0 / 60.0;  // Fixed 60 FPS update
        double targetRenderTime = 1.0 / 160.0;  // User-defined render FPS

#ifdef DEER_RENDER
        Function renderCallback;
        EventFunction eventCallback;
		Scope<Window> window;
		Scope<ImGuiLayer> imGuiLayer;
#endif

		void setTickCallback(Function _tick) {
            tickCallback = _tick;
        }

#ifdef DEER_RENDER
		void setRenderCallback(Function _render) {
            renderCallback = _render;
        }

        void setEventCallback(EventFunction _event) {
            eventCallback = _event;
        }

        Window& getWindow() {
            return *window;
        }

		void initWindow() {
            window = Scope<Window>(Window::create());
            imGuiLayer = MakeScope<ImGuiLayer>();
            
            window->initWindow();
            imGuiLayer->onAttach();

            if (eventCallback)
                window->setEventCallback(eventCallback);

		    RenderUtils::initializeRenderUtils();
		    RenderCommand::init();
        }

		void shutdownWindow() {
            imGuiLayer->onDetach();

            window.reset();
            imGuiLayer.reset();
        }
#endif

        void run() {
            running = true;

            auto previousTime = std::chrono::high_resolution_clock::now();
            double accumulatedUpdateTime = 0.0;
            double accumulatedRenderTime = 0.0;

            while (running) {
                // Time handling
                auto currentTime = std::chrono::high_resolution_clock::now();
                std::chrono::duration<double> deltaTime = currentTime - previousTime;
                previousTime = currentTime;

                accumulatedUpdateTime += deltaTime.count();
                accumulatedRenderTime += deltaTime.count();

                // Fixed Update loop (60 FPS)
                while (accumulatedUpdateTime >= targetUpdateTime) {
                    Timestep timestep = (float)targetUpdateTime;
                    accumulatedUpdateTime -= targetUpdateTime;

                    if (tickCallback)
                        tickCallback();
                    
                }

#ifdef DEER_RENDER
                // Render loop (User-defined FPS)
                if (accumulatedRenderTime >= targetRenderTime && tickCallback) {
                    RenderCommand::setClearColor({ 0.2f, 0.2f, 0.3f, 1.0f });
                    RenderCommand::clear();

                    ImGuiIO& io = ImGui::GetIO();
                    io.DeltaTime = (float)targetRenderTime;
                    imGuiLayer->begin();

                    tickCallback();
                    
                    imGuiLayer->end();
                    accumulatedRenderTime -= targetRenderTime;

                }

                window->resolveEvents();
#endif  

                std::this_thread::sleep_for(std::chrono::milliseconds(1));
            }
        }
    }
}