/*
 * Display.cpp
 *
 *  Created on: 4 nov. 2020
 *      Author: simon
 */

#include "client/window/Display.h"
#define GLFW_INCLUDE_NONE
#include "client/render/gui/TowerGui.h"
#include <iostream>
#include "td/game/GameManager.h"
#include "client/render/Renderer.h"
#include "client/render/WorldRenderer.h"
#include "../render/gui/imgui/imgui_impl_sdl.h"
#include "td/misc/Log.h"
#include "td/misc/Format.h"

#include <SDL2/SDL.h>
#include <SDL2/SDL_video.h>
#include <SDL2/SDL_render.h>

namespace Display {

static SDL_Window* window;
static SDL_GLContext glContext;

static constexpr int WindowWidth = 800;
static constexpr int WindowHeight = 600;
static constexpr const char WindowName[] = "Tower Defense";

std::unique_ptr<td::render::Renderer> renderer = std::make_unique<td::render::Renderer>();
std::unique_ptr<td::render::TowerGui> towerGui;

static int lastWidth = 0, lastHeight = 0;
static float aspectRatio;

static bool shouldClose = false;

void WindowResizeEvent(int width, int height) {
	aspectRatio = (float)width / height;
	renderer->Resize(width, height);
	lastWidth = width;
	lastHeight = height;
}

bool Create() {
	window = SDL_CreateWindow(WindowName, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, WindowWidth, 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
	SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5);
	SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 6);
	SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5);
	SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 0);

	SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
	SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);

	glContext = SDL_GL_CreateContext(window);

	if (!glContext) {
		std::cerr << "Could not create context! SDL error: " << SDL_GetError() << std::endl;
		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 = "?";
	}

	td::utils::LOG(td::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(window, glContext);

	if (!renderer->Init()) {
		exit(1);
	}
	towerGui = std::make_unique<td::render::TowerGui>(window, glContext, renderer.get());
	WindowResizeEvent(WindowWidth, WindowHeight);
	return true;
}

void Render() {
	renderer->Prepare();
	towerGui->Render();
}

void Update() {
	SDL_GL_SwapWindow(window);
}

void Destroy() {
	renderer.reset(0);
	towerGui.reset(0);
	SDL_GL_DeleteContext(glContext);
	SDL_DestroyWindow(window);
	SDL_Quit();
	window = NULL;
}

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

			case SDL_WINDOWEVENT_RESIZED: {
					int windowWidth, windowHeight;
					SDL_GetWindowSize(window, &windowWidth, &windowHeight);
					WindowResizeEvent(windowWidth, windowHeight);
				}

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

bool IsCloseRequested() {
	return shouldClose;
}

bool IsMouseDown(int button) {
	return ImGui::GetIO().MouseDown[button];
}

float GetAspectRatio() {
	return aspectRatio;
}

int GetWindowWidth() {
	return lastWidth;
}
int GetWindowHeight() {
	return lastHeight;
}

}

