/*
 * 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/.
 */

#include "PerformanceInfo.hpp"
#include "Base/FrameMetadata.hpp"
#include "Base/Utils.hpp"
#include "Host/SystemInfo.hpp"
#include "Math/ByteSize.hpp"
#include "ImGuiExtensions/ImGuiTextFmt.hpp"
#include "ImGuiExtensions/ImGuiPlotTwoLines.hpp"

#include <assert.h>

namespace OpenVulkano::Scene::UI
{
	namespace
	{
		float FloatCollectionValuesGetter(void *data, int index)
		{
			auto collection = static_cast<FloatCollection *>(data);
			float value = collection->m_values[index];
			float result = value / collection->m_maxValue * 100;
			return result;
		}
	}

	void PerformanceInfo::UpdateQueues()
	{
		float newFrameTime = static_cast<float>(CURRENT_FRAME.frameTime);
		if(newFrameTime > m_frames.m_maxValue)
			m_frames.m_maxValue = newFrameTime;

		m_frames.m_values.push_back(newFrameTime);

		while(m_frames.m_values.size() > m_windowSize)
		{
			float poppedFrameTime = m_frames.m_values.front();
			m_frames.m_values.pop_front();
			if(m_frames.m_maxValue == poppedFrameTime)
			{
				m_frames.m_maxValue = FLT_MIN;
				for(auto value : m_frames.m_values)
				{
					if(value > m_frames.m_maxValue)
						m_frames.m_maxValue = value;
				}
			}
		}

		m_ramUsed.m_values.push_back(static_cast<float>(SystemInfo::GetAppRamUsed()));
		while(m_ramUsed.m_values.size() > m_windowSize)
			m_ramUsed.m_values.pop_front();

		m_ramUsed.m_maxValue = SystemInfo::GetAppRamMax();

		assert(m_ramUsed.m_values.size() <= m_windowSize);
	}

	void PerformanceInfo::BeginDraw()
	{
		bool alwaysShow = true;
		ImGui::Begin("Performance Info", &alwaysShow);
	}

	void PerformanceInfo::Draw()
	{
		UpdateQueues();
		assert(m_frames.m_values.size() == m_ramUsed.m_values.size());

		ImGui::Text("Last Frame Time: %f s, max: %f s", m_frames.m_values.back(), m_frames.m_maxValue);
		ImGui::Text("Last FPS: %f", 1 / m_frames.m_values.back());
		ImGui::TextFmt("RAM: {} / {}, Free: {}", ByteSize(m_ramUsed.m_values.back()), ByteSize(SystemInfo::GetAppRamMax()), ByteSize(SystemInfo::GetAppRamAvailable()));
		ImGui::SliderInt("Window Size", &m_windowSize, 10, 1000);

		ImVec2 availableSize = ImGui::GetContentRegionAvail();
		float scaleMin = 0.01;
		float scaleMax = 100;
		ImGui::PlotTwoLines("",
			&FloatCollectionValuesGetter, &m_frames, "Frame Time(wrt max)",
			&FloatCollectionValuesGetter, &m_ramUsed, "RAM",
			(int)m_ramUsed.m_values.size(),
			scaleMin, scaleMax, availableSize);
	}

	void PerformanceInfo::EndDraw()
	{
		ImGui::End();
	}
}