/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/.
 */

#pragma once

#include "Base/IGraphicsAppManager.hpp"
#include "Base/IGraphicsApp.hpp"
#include "Base/Render/IRenderer.hpp"
#include "Base/UI/IWindow.hpp"
#include "Base/PlatformEnums.hpp"
#include "Base/Timer.hpp"
#include <string>
#include <memory>

namespace OpenVulkano
{
	class IPlatform;
	namespace Input
	{
		class InputManager;
	}
	class EngineConfiguration;

	/**
	 * \brief A simple GraphicsAppManager. It can only handle one window.
	 */
	class GraphicsAppManager final : public IGraphicsAppManager, public IWindowHandler
	{
	private:
		std::unique_ptr<IPlatform> platform;
		std::unique_ptr<IRenderer> renderer;
		IWindow* window;
		IGraphicsApp* app;
		RenderAPI::RenderApi renderApi;
		bool paused = false, running = false;
		float fpsTimer = 0, avgFps = 0, avgFrameTime = 0;
		uint64_t frameCount = 0, lastFrameCount = 0;
		std::chrono::microseconds cappedFrameTime = std::chrono::microseconds(0);
		Timer frameTimer;
		std::string windowTitleFormat;
		Input::InputManager* inputManager;
		EngineConfiguration* engineConfig;

	private:
		void OnCappedFPS(const auto& frameStartTime);
		void UpdateCappedFpsInfo(int32_t newFpsCap);
	public:
		explicit GraphicsAppManager(IGraphicsApp* app, RenderAPI::RenderApi renderApi = RenderAPI::Vulkan);

		explicit GraphicsAppManager(IGraphicsApp* app, IWindow* window, RenderAPI::RenderApi renderApi = RenderAPI::Vulkan);

		~GraphicsAppManager() noexcept override;

	public: // Getter
		[[nodiscard]] RenderAPI::RenderApi GetRenderApi() const override { return renderApi; }

		[[nodiscard]] IGraphicsApp* GetGraphicsApp() const override { return app; }

		[[nodiscard]] IRenderer* GetRenderer() const override { return renderer.get(); }

		[[nodiscard]] IWindow* GetWindow() const override { return window; }

		[[nodiscard]] bool IsRunning() const override { return running; }

		[[nodiscard]] bool IsPaused() const override { return paused; }

	public: // Setter
		void Stop() override;

		void Pause() override;

		void Resume() override;

	public:
		void Run() override;

	//private:
		void StartUp();

		void Loop();

		void LoopTick();

		void ShutDown();

		void UpdateFps();

	public: //FPS stuff
		[[nodiscard]] uint64_t GetFrameCount() const override { return frameCount; }

		[[nodiscard]] float GetAvgFrameTime() const override { return avgFrameTime; }

		[[nodiscard]] float GetAvgFps() const override { return avgFps; }

	public: // Window Manager
		void OnWindowMinimize(IWindow* window) override;

		void OnWindowRestore(IWindow* window) override;

		void OnWindowFocusLost(IWindow* window) override;
		void OnWindowFocusGained(IWindow* window) override;
		void OnWindowMove(IWindow* window, int posX, int posY) override;

		void OnWindowResize(IWindow* window, uint32_t newWidth, uint32_t newHeight) override;

		void OnWindowClose(IWindow* window) override;
	};
}
