#include "gameScreen.h"
#include "game.h"
#include "world.h"
#include "bullets.h"
#include "assets.h"
#include "entitiesInclude.h"

void initGameScreenGui(GameScreen * gameScreen) {
	float width = GetScreenWidth();
	float height = GetScreenHeight();

	// It is kind of terrible but works.
	gameScreen->infoTextPosition = (Vector2){0.0, height / 1.5};

	gameScreen->targetInfoPosition = (Vector2){
		width - (GAME_SCREEN_TEXT_SIZE * (GAME_SCREEN_TARGET_INFO_MAX / 2.0)),
		height / 3.0
	};

	// Gyroscope indeed
	initGyroscope(&gameScreen->gyroscope);

	// Radar indeed.
	initRadar(&gameScreen->radar);

	gameScreen->mainCamera = FIRST_PERSON_CAMERA;
	gameScreen->levelComplete = false;
}

void initGameScreen(Game * game, GameScreen * gameScreen) {
	initGameScreenGui(gameScreen);

	if (game->settings.useWorldRenderTexture) {
		gameScreen->worldRender = LoadRenderTexture(game->settings.renderWidth, game->settings.renderHeight);
		gameScreen->usingWorldRenderTexture = true;
	} else {
		gameScreen->usingWorldRenderTexture = false;
	}
}

void freeGameScreen(GameScreen * gameScreen) {
	closeGyroscope(&gameScreen->gyroscope);
	closeRadar(&gameScreen->radar);

	if (gameScreen->usingWorldRenderTexture)
		UnloadRenderTexture(gameScreen->worldRender);
}

void drawCrossHair(float size, float thick, Color color) {
	Vector3 center = (Vector3){GetScreenWidth() / 2.0, GetScreenHeight() / 2.0};

	// Left to right.
	DrawLineEx(
		(Vector2){center.x - size, center.y},
		(Vector2){center.x + size, center.y},
		thick,
		color
	);

	// Top to bottom.
	DrawLineEx(
		(Vector2){center.x, center.y - size},
		(Vector2){center.x, center.y + size},
		thick,
		color
	);
}

void drawGameScreenInfoText(Game * game, GameScreen * gameScreen) {
	Entity * player = getEntityFromWorld(game->world, 0);

	Vector3 position = player->position;
	Vector3 velocity = player->velocity.velocity;

	// Hello reader. I fucking hate you!
	size_t bufSize = 255;
	char buf[bufSize];

	// Format text.
	snprintf(
		buf,
		bufSize,
		"Health %.2f\n\nX %.2f\nY %.2f\nZ %.2f\n\nSpeed %.2f",
		player->health,
		position.x,
		position.y,
		position.z,
		Vector3Length(velocity)
	);

	// Draw info text.
	DrawText(
		buf,
		gameScreen->infoTextPosition.x,
		gameScreen->infoTextPosition.y,
		GAME_SCREEN_TEXT_SIZE,
		GREEN
	);
}

void drawGameScreenTargetInfo(Game * game, GameScreen * gameScreen) {
	Entity * player = getEntityFromWorld(game->world, 0);
	AntifaShip * data = (AntifaShip*)player->data;

	size_t bufSize = 255;
	char buf[bufSize];

	// Format.
	snprintf(
		buf,
		bufSize,
		"Auto: %s",
		data->doAutoTarget ? "On" : "Off"
	);

	// Is auto targeting.
	if (data->doAutoTarget) {
		Entity * targetedEntity = getEntityFromWorld(game->world, data->targetedEntityId);

		if (targetedEntity != NULL) {
			char bufCopy[bufSize];
			strncpy(bufCopy, buf, bufSize);

			// Add more formatted text.
			snprintf(
				buf,
				bufSize,
				"%s\nId: %d@%x\nDistance: %.2f\nOn Target: %s",
				bufCopy,
				data->targetedEntityId,
				data->targetedEntityFingerprint,
				Vector3Distance(player->position, targetedEntity->position),
				data->isOnTarget ? "Yes" : "No"
			);
		}
	}

	// Draw.
	DrawText(
		buf,
		gameScreen->targetInfoPosition.x,
		gameScreen->targetInfoPosition.y,
		GAME_SCREEN_TEXT_SIZE,
		GREEN
	);
}

void drawGameScreenGui(Game * game) {
	GameScreen * gameScreen = &game->gameScreen;

	// Draw cross hair.
	if (gameScreen->mainCamera == FIRST_PERSON_CAMERA) {
		// Get color depending if on target or not.
		Entity * player = getEntityFromWorld(game->world, 0);
		AntifaShip * data = (AntifaShip*)player->data;
		Color color = data->isOnTarget ? RED : BLUE;

		drawCrossHair(10.0, 2.0, color);
	}

	drawGameScreenInfoText(game, gameScreen);
	drawGameScreenTargetInfo(game, gameScreen);
	drawGyroscope(game, &gameScreen->gyroscope);
	drawRadar(game, &gameScreen->radar);
}

void handleGameScreenInput(Game * game, GameScreen * gameScreen) {
	switch(GetKeyPressed()) {
		case KEY_ONE:
			gameScreen->mainCamera = FIRST_PERSON_CAMERA;
			break;
		case KEY_TWO:
			gameScreen->mainCamera = THIRD_PERSON_CAMERA;
			break;
		case KEY_THREE:
			gameScreen->mainCamera = DEBUG_CAMERA;
			break;
		default:
			break;
	}
}

void drawNextLevelScreen(Game * game, GameScreen * gameScreen) {
	float width = GetScreenWidth();
	float height = GetScreenHeight();

	size_t bufSize = 100;
	char buf[bufSize];

	// Complete message.
	snprintf(
		buf,
		bufSize,
		"Level %d complete",
		game->levels.currentLevel + 1
	);

	DrawText(
		buf,
		(width / 2.0) - (50.0 * strnlen(buf, bufSize) / 4.0),
		height / 3.0,
		50,
		GREEN
	);
}

void gameScreenHandleLevels(Game * game, GameScreen * gameScreen) {
	// Show complete screen if level complete.
	if (gameScreen->levelComplete) {
		drawNextLevelScreen(game, gameScreen);

		// Next fucking level.
		if (GetTime() - gameScreen->timeAtLevelComplete >= GAME_SCREEN_NEXT_LEVEL_DELAY) {
			gameScreen->levelComplete = false;
			startLevel(game, &game->levels, gameScreen->lastLevel + 1);
		}

		return;
	}

	bool complete = updateLevel(game, &game->levels);

	// This fucker been completed.
	if (complete) {
		gameScreen->lastLevel = game->levels.currentLevel;
		endLevel(game, &game->levels);
		gameScreen->levelComplete = true;
		gameScreen->timeAtLevelComplete = GetTime();
	}
}

void renderWorldGameScreen(Game * game, GameScreen * gameScreen) {
	BeginMode3D(game->cameras[gameScreen->mainCamera]);

	//DrawGrid(50, 25.0);

	// Draw world.
	drawWorld(&game->world, game);

	EndMode3D();
}

void updateGameScreen(Game * game) {
	GameScreen * gameScreen = &game->gameScreen;

	handleGameScreenInput(game, gameScreen);

	ClearBackground(BLACK);
	
	// Levels indeed.
	gameScreenHandleLevels(game, gameScreen);

	if (gameScreen->levelComplete)
		return;

	// Update world.
	updateWorld(&game->world, game);

	// Camera.
	runCameraUpdate(game, game->cameras, gameScreen->mainCamera);

	// Draw world.
	if (gameScreen->usingWorldRenderTexture) {
		BeginTextureMode(gameScreen->worldRender);
		ClearBackground(BLACK);
		renderWorldGameScreen(game, gameScreen);
		EndTextureMode();

		DrawTexturePro(
			gameScreen->worldRender.texture,
			(Rectangle){0.0, 0.0, game->settings.renderWidth, -game->settings.renderHeight},
			(Rectangle){0.0, 0.0, GetScreenWidth(), GetScreenHeight()},
			(Vector2){0.0, 0.0},
			0.0,
			WHITE
		);
	} else {
		renderWorldGameScreen(game, gameScreen);
	}

	// GUI.
	drawGameScreenGui(game);
}

void openGameScreen(Game * game) {
	game->screenId = SCREEN_GAME;

	if (game->settings.lockMouse)
		DisableCursor();
}

void closeGameScreen(Game * game) {
	if (game->settings.lockMouse)
		EnableCursor();
}