// ::Game::Globals::Start::

// TEMP

u32 selected_rect = 0;
b8 mouse_pressed = false;
b8 mouse_clicked = false;
i16 mouse_prev_pos_x = 0;
i16 mouse_prev_pos_y = 0;
i16 mouse_pos_x = 0;
i16 mouse_pos_y = 0;

// ::Game::Globals::End::



// ::Game::Init::Functions::Start::

static void gInit(gGameCtx *ctx) 
{
  Assert(rInit(), "Failed to initialize the renderer");

	ctx->arena = ArenaCreateDebug(MB(16), __LINE__);

	ctx->gui.vertices = MakeArray(ctx->arena, rUIVertex, 128);
	ctx->gui.vertices_len = 0;
	ctx->gui.indices = MakeArray(ctx->arena, u32, 768);
	ctx->gui.indices_len = 0;
	ctx->gui.instance_count = 0;

	ctx->windows = MakeArray(ctx->arena, gWindowWidget, 32);
	ctx->window_len = 0;

	ctx->buttons = MakeArray(ctx->arena, gButtonWidget, 64);
	ctx->btn_len = 0;
}

static void gDestroy()
{
	rDestroy();
}

// ::Game::Init::Functions::End::



// ::Game::GameLoop::Functions::Start::

static void gFrameStartNew()
{
	
}

static void gRunCycle(gGameCtx *ctx, pGameInput *inputs, u32 i_count)
{
	ArenaFree(vFrameArena());

	gPrepareGUICtx(ctx);

	gHandleInputs(inputs, i_count);
	
	rFrameBegin();

	vTextureCleanUp();

	/*
	if (gButton(ctx, "Show 2", 150.0f, 150.0f, 200.0f, 200.0f))
	{
		gWindow(ctx, "Window 2", 500.0f, 500.0f, 600.0f, 600.0f);
	}

	if (gButton(ctx, "Show 1", 50.0f, 50.0f, 100.0f, 100.0f))
	{
		gWindow(ctx, "Window 1", 200.0f, 200.0f, 400.0f, 400.0f);
	}

	if (gButton(ctx, "Show 3", 150.0f, 300.0f, 200.0f, 350.0f))
	{
		gWindow(ctx, "Window 3", 250.0f, 500.0f, 400.0f, 650.0f);
	}
	*/

	u64 index = vFrameIndex();
	rDescHandle texture;
	if (index == 0)
		texture = rTextureLoad(HAMSMOKER);
	else
		texture = rTextureLoad(HOG);

	rTextureUnload(texture);

	rViewportSize(&ctx->pc.res);
	ctx->pc.time = (f32)pCPUTimerRead();

	gWindow(ctx, "texture", 100.0f, 100.0f, 300.0f, 300.0f, texture);

	rawptr vert_buffer = rBufferGUIVertMapping();
	rawptr idx_buffer = rBufferGUIIdxMapping();

	MemCpy(vert_buffer, ctx->gui.vertices, sizeof(rUIVertex) * ctx->gui.vertices_len);
	MemCpy(idx_buffer, ctx->gui.indices, sizeof(u32) * ctx->gui.indices_len);

	vBufferQueueWait();

	rPipelineBind(R_PIPELINE_GUI, rPT_GRAPHICS);

	rPushConstantsSet(&ctx->pc);

	rBufferBindGUIVertex();
	rBufferBindGUIIndex();

	rDrawIndexed(6, ctx->gui.instance_count);

	rFrameFinish();

	ctx->gui.vertices_len = 0;
	ctx->gui.indices_len = 0;
	ctx->gui.instance_count = 0;
	ArenaFree(ctx->arena);
}

// ::Game::GameLoop::Functions::End::



// ::Game::Inputs::Functions::Start::

static void gHandleInputs(pGameInput *inputs, u32 count)
{
	mouse_clicked = false;

	for (u32 i = 0; i < count; i++)
	{
		if (inputs[i].type == GI_KEYBOARD)
		{
			if (inputs[i].kb_code == KB_1) 
			{
				selected_rect = 0;
				break;
			}
			else if (inputs[i].kb_code == KB_2) 
			{
				selected_rect = 1;
				break;
			}
			else if (inputs[i].kb_code == KB_3) 
			{
				selected_rect = 2;
				break;
			}
			else if (inputs[i].kb_code == KB_4) 
			{
				selected_rect = 3;
				break;
			}
		}
		else if (inputs[i].type == GI_MOUSE)
		{
			if (inputs[i].m_code == M_LEFT_CLICK)
			{
				mouse_pressed = inputs[i].pressed;
				if (!inputs[i].pressed)
					mouse_clicked = true;
			}
		}
		else if (inputs[i].type == GI_MOTION)
		{
			mouse_prev_pos_x = mouse_pos_x;
			mouse_prev_pos_y = mouse_pos_y;
			mouse_pos_x = inputs[i].motion_ev.x;
			mouse_pos_y = inputs[i].motion_ev.y;
		}
	}
}

// ::Game::Inputs::Functions::End::



// ::Game::GUI::Functions::Start::

static inline void gPrepareGUICtx(gGameCtx *ctx)
{
	ctx->gui.has_grabbed = false;
}

static b32 gButton(gGameCtx *ctx, char *label, f32 x0, f32 y0, f32 x1, f32 y1)
{
	gButtonWidget *btn = NULL;
	u64 id = HashFromString(String8CStr(label));
	if (ctx->btn_len == 0)
	{
		ctx->buttons[0].p0.x = x0;
		ctx->buttons[0].p0.y = y0;
		ctx->buttons[0].p1.x = x1;
		ctx->buttons[0].p1.y = y1;
		ctx->buttons[0].id = id;
		ctx->buttons[0].pressed = false;
		ctx->buttons[0].pressed_prev = false;

		btn = &ctx->buttons[0];
		ctx->btn_len += 1;
	}
	else 
	{
		for (u32 i = 0; i < ctx->btn_len; i++)
		{
			if (ctx->buttons[i].id == id)
			{
				btn = &ctx->buttons[i];
				break;
			}
		}

		if (btn == NULL)
		{
			ctx->btn_len += 1;
			btn = &ctx->buttons[ctx->btn_len];

			btn->p0.x = x0;
			btn->p0.y = y0;
			btn->p1.x = x1;
			btn->p1.y = y1;
			btn->id = id;
			btn->pressed = false;
			btn->pressed_prev = false;
		}
	}

	Assert(btn != NULL, "button is null");

	if (mouse_clicked
		  && !ctx->gui.has_grabbed
			&& mouse_pos_x > btn->p0.x
			&& mouse_pos_x < btn->p1.x
			&& mouse_pos_y > btn->p0.y
			&& mouse_pos_y < btn->p1.y)
	{
		btn->pressed = !btn->pressed;
	}

	//gRect(&ctx->gui, btn->p0, btn->p1, (Vec4){ .r = 0.1f, .g = 0.9f, .b = 0.4f, .a = 1.0f });

	return btn->pressed;
}

static b32 gWindow(gGameCtx *ctx, char *title, f32 x0, f32 y0, f32 x1, f32 y1, rDescHandle handle)
{
	gWindowWidget *win = NULL;
	u32 id = HashFromString(String8CStr(title));
	if (ctx->window_len == 0)
	{
		ctx->windows[0].p0.x = x0;
		ctx->windows[0].p0.y = y0;
		ctx->windows[0].p1.x = x1;
		ctx->windows[0].p1.y = y1;
		ctx->windows[0].id = id;

		win = &ctx->windows[0];
		ctx->window_len += 1;
	}
	else 
	{
		for (u32 i = 0; i < ctx->window_len; i++)
		{
			if (ctx->windows[i].id == id)
			{
				win = &ctx->windows[i];
				break;
			}
		}

		if (win == NULL)
		{
			ctx->window_len += 1;
			win = &ctx->windows[ctx->window_len];

			win->p0.x = x0;
			win->p0.y = y0;
			win->p1.x = x1;
			win->p1.y = y1;
			win->id = id;
		}
	}

	Assert(win != NULL, "window is null");

	if (mouse_pressed && !win->grabbed 
		&& mouse_pos_x > win->p0.x 
		&& mouse_pos_x < win->p1.x 
		&& mouse_pos_y > win->p0.y
		&& mouse_pos_y < win->p1.y
		&& !ctx->gui.has_grabbed)
	{
		win->grabbed = true;
		ctx->gui.has_grabbed = true;

		win->grabbed_pos.x = (f32)mouse_pos_x - win->p0.x;
		win->grabbed_pos.y = (f32)mouse_pos_y - win->p0.y;
	}
	else if (!mouse_pressed && win->grabbed)
	{
		win->grabbed = false;

		win->grabbed_pos.x = 0.0f;
		win->grabbed_pos.y = 0.0f;
	}

	if (win->grabbed)
	{
		f32 w = win->p1.x - win->p0.x;
		f32 h = win->p1.y - win->p0.y;

		win->p0.x = (f32)(mouse_pos_x) - win->grabbed_pos.x;
		win->p0.y = (f32)(mouse_pos_y) - win->grabbed_pos.y;
		win->p1.x = win->p0.x + w;
		win->p1.y = win->p0.y + h;

		ctx->gui.has_grabbed = true;
	}

	gRect(&ctx->gui, win->p0, win->p1, (Vec4){ .r = 0.1f, .g = 0.3f, .b = 0.8f, .a = 1.0f }, handle);

	return true;
}


static void gRect(gUICtx *ctx, Vec2 p0, Vec2 p1, Vec4 col, rDescHandle handle)
{
	ctx->vertices[ctx->vertices_len].p0 = p0;
	ctx->vertices[ctx->vertices_len].p1 = p1;
	ctx->vertices[ctx->vertices_len].col = col;
	ctx->vertices[ctx->vertices_len].tex_idx = handle.desc_index;
	
	ctx->vertices_len += 1;

	ctx->indices[ctx->indices_len] 		= ctx->indices_len;
	ctx->indices[ctx->indices_len+1]	= ctx->indices_len+1;
	ctx->indices[ctx->indices_len+2] 	= ctx->indices_len+2;
	ctx->indices[ctx->indices_len+3] 	= ctx->indices_len+1;
	ctx->indices[ctx->indices_len+4]	= ctx->indices_len+2;
	ctx->indices[ctx->indices_len+5] 	= ctx->indices_len+3;
	
	ctx->indices_len += 6;

	ctx->instance_count += 1;
}

// ::Game::GUI::Functions::End::
