#include "client/render/Display.h"

#include <GL/glew.h>
#include <SDL2/SDL.h>
#include <backends/imgui_impl_opengl3.h>
#include <backends/imgui_impl_sdl2.h>

#include "blitz/misc/Format.h"
#include "blitz/misc/Log.h"

#include "client/gui/BlitzGui.h"

namespace blitz {

Display::Display(int width, int height, const std::string& windowName, Client* client) :
	m_WindowWidth(width),
	m_WindowHeight(height),
	m_WindowName(windowName),
	m_ShouldClose(false),
	m_FullScreen(false),
	m_AspectRatio(m_WindowHeight / static_cast<float>(m_WindowWidth)),
	m_Client(client),
	m_BlitzGui(nullptr) {}

Display::~Display() {
	Destroy();
}

bool Display::Create() {

	m_Window = SDL_CreateWindow(m_WindowName.c_str(), SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, m_WindowWidth, m_WindowHeight,
		SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
	// Prepare and create context
#ifdef __ANDROID__
	SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
	SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
	SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
#else
	SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
	SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
	SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
#endif

	m_GL_Context = SDL_GL_CreateContext(m_Window);

	if (!m_GL_Context) {
		utils::LOGE(utils::Format("Could not create context ! SDL error : %s", SDL_GetError()));
		return false;
	}

	int major, minor, mask;
	int r, g, b, a, depth;
	SDL_GL_GetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, &mask);
	SDL_GL_GetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, &major);
	SDL_GL_GetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, &minor);

	SDL_GL_GetAttribute(SDL_GL_RED_SIZE, &r);
	SDL_GL_GetAttribute(SDL_GL_GREEN_SIZE, &g);
	SDL_GL_GetAttribute(SDL_GL_BLUE_SIZE, &b);
	SDL_GL_GetAttribute(SDL_GL_ALPHA_SIZE, &a);

	SDL_GL_GetAttribute(SDL_GL_DEPTH_SIZE, &depth);

	const char* mask_desc;

	if (mask & SDL_GL_CONTEXT_PROFILE_CORE) {
		mask_desc = "core";
	} else if (mask & SDL_GL_CONTEXT_PROFILE_COMPATIBILITY) {
		mask_desc = "compatibility";
	} else if (mask & SDL_GL_CONTEXT_PROFILE_ES) {
		mask_desc = "es";
	} else {
		mask_desc = "?";
	}

	utils::LOG(utils::Format(
		"GL Context : %i.%i %s, Color : R:%i G:%i B:%i A:%i, Depth bits : %i", major, minor, mask_desc, r, g, b, a, depth));

	SDL_GL_MakeCurrent(m_Window, m_GL_Context);
	SDL_GL_SetSwapInterval(1);

	GLenum err = glewInit();
	if (GLEW_OK != err) {
		utils::LOGE(utils::Format("Error: %s", glewGetErrorString(err)));
	}

	InitImGui();
	return true;
}

void Display::PollEvents() {
	SDL_Event event;
	while (SDL_PollEvent(&event)) {
		if (event.type == SDL_WINDOWEVENT) {
			switch (event.window.event) {
				case SDL_WINDOWEVENT_CLOSE: {
					m_ShouldClose = true;
					break;
				}

				case SDL_WINDOWEVENT_RESIZED: {
					SDL_GetWindowSize(m_Window, &m_WindowWidth, &m_WindowHeight);
					m_AspectRatio = m_WindowHeight / static_cast<float>(m_WindowWidth);
					break;
				}

				default:
					break;
			}
		}
		if (event.type == SDL_KEYDOWN) {
			switch (event.key.keysym.scancode) {
				case SDL_SCANCODE_F11: {
					m_FullScreen = !m_FullScreen;
					SDL_SetWindowFullscreen(m_Window, m_FullScreen);
					break;
				}

				default:
					break;
			}
		}
		ImGui_ImplSDL2_ProcessEvent(&event);
	}

	ImGui_ImplOpenGL3_NewFrame();
	ImGui_ImplSDL2_NewFrame();
	ImGui::NewFrame();
}

void Display::Update() {
	ImGui::Render();
	ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
	SDL_GL_SwapWindow(m_Window);
	glClear(GL_COLOR_BUFFER_BIT);
}

void Display::Render() {

	m_BlitzGui->Render();

#if !defined(NDEBUG)
	ImGui::ShowDemoWindow();
#endif
}

void Display::Destroy() {
	if (m_Window == nullptr)
		return;

	SDL_GL_DeleteContext(m_GL_Context);
	SDL_DestroyWindow(m_Window);
	SDL_Quit();
	m_Window = nullptr;
	m_GL_Context = nullptr;
}

bool Display::IsCloseRequested() {
	return m_ShouldClose;
}

float Display::GetAspectRatio() {
	return m_AspectRatio;
}

int Display::GetWindowWidth() {
	return m_WindowWidth;
}

int Display::GetWindowHeight() {
	return m_WindowHeight;
}

void Display::InitImGui() {
	IMGUI_CHECKVERSION();
	ImGui::CreateContext();
	ImGui::StyleColorsDark();
	ImGui_ImplSDL2_InitForOpenGL(m_Window, m_GL_Context);
	ImGui_ImplOpenGL3_Init();

	ImFontConfig c;
	c.SizePixels = 25;
	ImGui::GetIO().Fonts->AddFontDefault(&c);
	// doom font
	auto* doomFont = ImGui::GetIO().Fonts->AddFontFromFileTTF("doom.ttf", 25);
	ImGui::GetIO().FontDefault = doomFont;

	ImGui::GetIO().ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;

	m_BlitzGui = std::make_unique<gui::BlitzGui>(m_Client);
}

}  // namespace blitz
