#include "pch.h"
#include "IO.h"

#include <game/Text.h>

#include "Drawer2D.h"
#include "Engine.h"
#include "EditorNew.h"
#include "gl/WGL.h"

KeyState IO::get_key(WPARAM key) {
	if (this->key_map.contains(key)) {
		return key_map[key];
	} else {
		return KeyState();
	}
}
KeyState IO::get_key(Key key) {
	return this->get_key((WPARAM)key);
}

	bool IO::handle_input(UINT msg, WPARAM wParam) {
	
		for(auto& k : key_map){
			if(k.second.down){
				k.second.t_since_press += WEngine->delta_time;
			}
		}

		auto lambda_get_key_state = [this](WPARAM _wparam) -> KeyState* {
			// if(key_map.count(_wparam) == 0) {
			if (!key_map.contains(_wparam)) {
				key_map[_wparam] = KeyState();
			}
			return &key_map[_wparam];
		};
		switch (msg) {
			// case WM_NCPAINT:
				// Remove the icon by invalidating the title bar
					// DefWindowProc(WEngine->wgl->hwnd, msg, wParam, lParam);
			// {
			// 	HDC hdc = WEngine->wgl->hDC;
			// 	if (hdc) {
			// 		RECT rect;
			// 		GetWindowRect(WEngine->wgl->hwnd, &rect);
			// 		rect.right -= rect.left;
			// 		rect.bottom -= rect.top;
			// 		rect.left = rect.top = 0;
			//
			// 		// Draw the title bar without the icon
			// 		FillRect(hdc, &rect, GetSysColorBrush(COLOR_ACTIVECAPTION));
			// 		// DrawText(hdc, TEXT("Test Window"), -1, &rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX);
			// 		// ReleaseDC(WEngine->wgl->hwnd, hdc);
			// 	}
			// }
			case WM_SIZE: {
				WEngine->editor->gui_dbg_print_msg("size");
				if ((wParam & 0xFFF0) == SC_MINIMIZE) {
					WEngine->editor->toStartPausedRendering = true;
				} else {
					WEngine->editor->toEndPausedRendering = true;
				}
			}
			case WM_MBUTTONDOWN: {
				if (!this->mouse_mmb_down) { this->mouse_mmb_just_pressed = true; }
				this->mouse_mmb_down = true;
				return true;
			}
			case WM_MBUTTONUP: {
				if (this->mouse_mmb_down) { this->mouse_mmb_just_unpressed = true; }
				this->mouse_mmb_down = false;
				return true;
			}
			case WM_LBUTTONDOWN: {
				if (!this->mouse_lmb_down) { this->mouse_lmb_just_pressed = true; }
				this->mouse_lmb_down = true;
				return true;
			}
			case WM_LBUTTONUP: {
				if (this->mouse_lmb_down) { this->mouse_lmb_just_unpressed = true; }
				this->mouse_lmb_down = false;
				return true;
			}
			case WM_RBUTTONDOWN: {
				if (!this->mouse_rmb_down) { this->mouse_rmb_just_pressed = true; }
				this->mouse_rmb_down = true;
				return true;
			}
			case WM_RBUTTONUP: {
				if (this->mouse_rmb_down) { this->mouse_rmb_just_unpressed = true; }
				this->mouse_rmb_down = false;
				return true;
			}
			case WM_CLOSE: {
				WEngine->editor->finished = true;
				// this->finished = true;
				return true;
			}
			case WM_DESTROY: {
				WEngine->editor->finished = true;
				// this->finished = true;
				return true;
			}
			case WM_KEYDOWN: {
				KeyState* key_state = lambda_get_key_state(wParam);
				if (!key_state->down) {
					key_state->just_pressed = true;
					key_state->down = true;
					key_state->t_since_press = 0.0f;
				}
				return true;
			}
			case WM_KEYUP: {
				KeyState* key_state = lambda_get_key_state(wParam);
				if (key_state->down) {
					key_state->just_unpressed = true;
					key_state->down = false;
				}
				return true;
			}
		}
		return false;
	}
	void IO::end_frame() {
		this->mouse_lmb_just_unpressed = false;
		this->mouse_lmb_just_pressed = false;
		this->mouse_rmb_just_unpressed = false;
		this->mouse_rmb_just_pressed = false;
		this->mouse_mmb_just_unpressed = false;
		this->mouse_mmb_just_pressed = false;
		for (auto& [key, key_state] : this->key_map) {
			key_state.just_pressed = false;
			key_state.just_unpressed = false;
		}
	}

void IO::handle_mouse() {
	// this->newMouse;

	if (!GetCursorPos(&this->newMouse))
		return;
	ScreenToClient(WEngine->wgl->hwnd, &this->newMouse);

	#ifdef EDITOR
	this->imgui_wants_mouse = WEngine->editor->imgui_io->WantCaptureMouse;
	#endif


	float newMouseX = float(this->newMouse.x) / float(WEngine->RESX);
	float newMouseY = float(this->newMouse.y) / float(WEngine->RESY);


	static float mouse_to_delta_x = 0.0;
	static float mouse_to_delta_y = 0.0;

	this->delta_mouse_x = newMouseX - mouse_to_delta_x;
	this->delta_mouse_y = newMouseY - mouse_to_delta_y;

	mouse_to_delta_x = this->mouse_x;
	mouse_to_delta_y = this->mouse_y;

	this->delta_mouse_x *= float(WEngine->RESX) / float(WEngine->RESY);
	
	this->delta_mouse_ndc = glm::vec2(this->delta_mouse_x, this->delta_mouse_y);

	mouse_x = newMouseX;
	mouse_y = newMouseY;


	mouse_uv.x = mouse_x;
	mouse_uv.y = mouse_y;

	mouse_ndc.x = mouse_x * 2.0f - 1.0f;
	mouse_ndc.y = -(mouse_y * 2.0f - 1.0f);

	if(this->get_key(Key::Tab).just_pressed) {
		this->set_mouse_grabbed(!this->mouse_grabbed);
	}
	if(!WEngine->io->window_focused && this->mouse_grabbed) {
		this->set_mouse_grabbed(false);
		// wlog_info("mouse ungrab");
	}
	// #if EDITOR
	// #endif

	if (this->mouse_grabbed) {
		// SetCursor(LoadCursor(NULL, IDC_ARROW));
		SetCursorPos(this->mouse_x_before_drag_start, this->mousy_y_before_drag_start);
		POINT mouse_before_drag_start = POINT(this->mouse_x_before_drag_start, this->mousy_y_before_drag_start);
		ScreenToClient(WEngine->wgl->hwnd, &mouse_before_drag_start);
		// PostMessage(WEngine->wgl->hwnd, WM_SETCURSOR, 0, 0);
		SetCursor(NULL);
		mouse_to_delta_x = float(mouse_before_drag_start.x)/float(WEngine->RESX);
		mouse_to_delta_y = float(mouse_before_drag_start.y)/float(WEngine->RESY);
	}
}

void IO::set_mouse_grabbed(bool state) {
	// if(!WEngine->io->window_focused && this->mouse_grabbed) {
	//
	// }
	if(this->mouse_grabbed == state) {
		return;
	}

	if ( !this->mouse_grabbed && !imgui_wants_mouse ) {
		// Start mouse grab
		auto newMouseScreen = newMouse;
		ClientToScreen(WEngine->wgl->hwnd, &newMouseScreen);
		this->mouse_x_before_drag_start = newMouseScreen.x;
		this->mousy_y_before_drag_start = newMouseScreen.y;
		this->mouse_grabbed = true;
		SetCursor(NULL);
	} else if (
		this->mouse_grabbed
	) {
		// Start mouse ungrab
		if (this->mouse_grabbed) {
			SetCursor(LoadCursor(NULL, IDC_ARROW));
			SetCursorPos(this->mouse_x_before_drag_start, this->mousy_y_before_drag_start);
		}
		this->mouse_grabbed = false;
	}
}


void IO::do_ui_elem(UIElem* elem, bool clickable = true) {
	elem->mouse_clicked = false;
	elem->mouse_unclicked = false;

	if(this->mouse_over(elem->rect) && clickable) {
		if(this->mouse_lmb_just_pressed) {
			if(!elem->mouse_down && clickable) {
				if(elem->on_mouse_clicked) { elem->on_mouse_clicked(elem); }
				elem->mouse_clicked = true;
			} else {
				elem->mouse_clicked = false;
			}
			elem->mouse_down = true;
		} else if (this->mouse_lmb_just_unpressed) {
			elem->mouse_unclicked = true;
			elem->mouse_down = false;
			if(elem->on_mouse_unclicked && clickable) { elem->on_mouse_unclicked(elem); }
		}
		if(this->mouse_lmb_down) {
			if(elem->on_mouse_down && clickable) { elem->on_mouse_down(elem); }
		} else {
			if(elem->on_mouse_over && clickable) {
				elem->on_mouse_over(elem);
			}
		}
	} else {
		// -- mouse not over
		if(elem->mouse_down) {
			elem->mouse_unclicked = true;
			elem->mouse_down = false;
			if(elem->on_mouse_unclicked && clickable) { elem->on_mouse_unclicked(elem); }
		}
		if(elem->on_mouse_not_over) {
			elem->on_mouse_not_over(elem);
		}
	}
	if(elem->render) {
		elem->render(elem);
	}
}

bool IO::mouse_over(RectangDescr rect) {
	auto sd_rect = [](glm::vec2 p, RectangDescr rect) -> float{
		
		p -= vec2(rect.pos);
		p = abs(p);
		p -= rect.sz;
		float sd = glm::max(p.y,p.x);
		return sd;
	};

	if(sd_rect(this->mouse_ndc, rect) < 0.0) {
		return true;
	} else {
		return false;
	}
}
