#include "pixelGameEngine.h"
#include "main.h"
using namespace olc;

extern FaceBall* game;

Editor::Editor() {
	map = LoadLevel(this->level);
	MAP_SIZE = { (int)map[0].size(),(int)map.size() };
}

std::string Editor::GetPowerupName(PowerupType type){
	switch (type){
		case PowerupType::ARMOR:{
			return "ARMOR";
		}break;
		case PowerupType::CAMO:{
			return "CAMO";
		}break;
		case PowerupType::COIN:{
			return "COIN";
		}break;
		case PowerupType::MAP:{
			return "MAP";
		}break;
		case PowerupType::SHIELD:{
			return "SHIELD";
		}break;
		case PowerupType::SHOTS:{
			return "SHOTS";
		}break;
		case PowerupType::SPEED:{
			return "SPEED";
		}break;
		case PowerupType::STOP:{
			return "STOP";
		}break;
	}
}

void Editor::Update(float fElapsedTime){
	MouseWheelEnemySelection();
	RenderLevel();
	WaveLayerSelection();
	game->DrawStringDecal({ 2,16 }, "Selected Enemy ("+std::to_string(selectedEnemy) + "): " + game->GetData(selectedEnemy).name + (game->GetData(selectedEnemy).powerupDrop!=PowerupType::NONE?"("+GetPowerupName(game->GetData(selectedEnemy).powerupDrop)+")":""), WHITE, {3,3});
	game->DrawStringDecal({ 2,(float)game->ScreenHeight() - 50 }, "Layer " + std::to_string(waveLayer), WHITE, { 5,5 });
	if (!game->IsTextEntryEnabled()) {
		if (game->GetKey(F3).bPressed) {
			SaveLevel();
			std::cout << "Level " << level << " Saved!" << std::endl;
		}
	}
	LoadLevelHandling();
}

void Editor::LoadLevelHandling() {
	if (!game->IsTextEntryEnabled()) {
		if (promptState == PromptState::NONE) {
			if (game->GetKey(F1).bPressed) {
				promptState = PromptState::ENTER_LEVEL;
				game->TextEntryEnable(true);
			}
			if (game->GetKey(F2).bPressed) {
				promptState = PromptState::ENTER_WIDTH;
				game->TextEntryEnable(true,std::to_string(MAP_SIZE.x));
			}
		}
		if (reEnableTextEntry) {
			switch (promptState) {
				case PromptState::ENTER_LEVEL: {
					game->TextEntryEnable(true);
				}break;
				case PromptState::ENTER_WIDTH: {
					game->TextEntryEnable(true, std::to_string(MAP_SIZE.y));
				}break;
				case PromptState::ENTER_HEIGHT: {
					game->TextEntryEnable(true,std::to_string(MAP_SIZE.y));
				}break;
			}
			reEnableTextEntry = false;
		}
	}
	else {
		game->FillRectDecal({ 0,0 }, { (float)game->ScreenWidth(),32 }, BLACK);
		switch (promptState) {
			case PromptState::ENTER_LEVEL: {
				game->DrawStringDecal({ 0,0 }, "Enter Level (1-30): " + game->TextEntryGetString(), WHITE, { 4,4 });
			}break;
			case PromptState::ENTER_WIDTH: {
				game->DrawStringDecal({ 0,0 }, "Enter Level Width: " + game->TextEntryGetString(), WHITE, { 4,4 });
			}break;
			case PromptState::ENTER_HEIGHT: {
				game->DrawStringDecal({ 0,0 }, "Enter Level Height: " + game->TextEntryGetString(), WHITE, { 4,4 });
			}break;
		}
	}
}

void Editor::MouseWheelEnemySelection()
{
	if (game->GetMouseWheel() != 0) {
		if (game->GetMouseWheel() > 0) {
			if (selectedEnemy < 63) {
				selectedEnemy = EnemyID(selectedEnemy + 1);
			}
			else {
				selectedEnemy = EnemyID::NONE;
			}
		}
		else {
			if (selectedEnemy > 0) {
				selectedEnemy = EnemyID(selectedEnemy - 1);
			}
			else {
				selectedEnemy = AREA_MAP;
			}
		}
	}
}

void Editor::RenderLevel()
{
	vf2d center = { -(float)MAP_SIZE.x / 2 * GRID_SIZE.x + game->ScreenWidth() / 2 , -(float)MAP_SIZE.y / 2 * GRID_SIZE.y + game->ScreenHeight() / 2 };
	for (int y = 0; y < MAP_SIZE.y; y++) {
		for (int x = 0; x < MAP_SIZE.x; x++) {
			Tile& t = map[y][x];
			vf2d squarePos = vf2d{ (float)x,(float)y }*GRID_SIZE + center;
			if (game->GetMouseX() >= squarePos.x && game->GetMouseX() <= squarePos.x + GRID_SIZE.x &&
				game->GetMouseY() >= squarePos.y && game->GetMouseY() <= squarePos.y + GRID_SIZE.y) {
				if (!game->IsTextEntryEnabled()) {
					if (game->GetKey(W).bPressed) {
						t.wallN = !t.wallN;
						if (y > 0) {
							Tile& neighbor = map[y - 1][x];
							neighbor.wallS = t.wallN;
						}
					}
					if (game->GetKey(D).bPressed) {
						t.wallE = !t.wallE;
						if (x < MAP_SIZE.x - 1) {
							Tile& neighbor = map[y][x + 1];
							neighbor.wallW = t.wallE;
						}
					}
					if (game->GetKey(S).bPressed) {
						t.wallS = !t.wallS;
						if (y < MAP_SIZE.y - 1) {
							Tile& neighbor = map[y + 1][x];
							neighbor.wallN = t.wallS;
						}
					}
					if (game->GetKey(A).bPressed) {
						t.wallW = !t.wallW;
						if (x > 0) {
							Tile& neighbor = map[y][x - 1];
							neighbor.wallE = t.wallW;
						}
					}
					if (game->GetMouse(0).bPressed) {
						t.enemyId = selectedEnemy;
						switch (waveLayer) {
						case 0: {
							t.wave1 = true;
						}break;
						case 1: {
							t.wave2 = true;
						}break;
						case 2: {
							t.wave3 = true;
						}break;
						}
						if (t.enemyId == EnemyID::NONE) {
							t.wave1 = t.wave2 = t.wave3 = false;
						}
					}
					if (game->GetMouse(1).bPressed) {
						switch (waveLayer) {
						case 0: {
							t.wave1 = false;
						}break;
						case 1: {
							t.wave2 = false;
						}break;
						case 2: {
							t.wave3 = false;
						}break;
						}
						if (!(t.wave1 || t.wave2 || t.wave3)) {
							t.enemyId = EnemyID::NONE;
						}
					}
					if (game->GetKey(DOWN).bHeld) {
						t.facingDir = FacingDirection::SOUTH;
					}
					if (game->GetKey(RIGHT).bHeld) {
						t.facingDir = FacingDirection::EAST;
					}
					if (game->GetKey(UP).bHeld) {
						t.facingDir = FacingDirection::NORTH;
					}
					if (game->GetKey(LEFT).bHeld) {
						t.facingDir = FacingDirection::WEST;
					}
				}
				game->FillRectDecal(squarePos, GRID_SIZE, { 0,0,255,64 });
			}
			//game->DrawRectDecal(squarePos,GRID_SIZE,{64,64,64});
			if (t.enemyId != EnemyID::NONE) {
				if (t.enemyId >= COIN) {
					game->DrawPolygonDecal(nullptr, {
							vf2d{0,(float)GRID_SIZE.y / 2} + squarePos ,
							vf2d{(float)GRID_SIZE.x / 2,0} + squarePos ,
							vf2d{(float)GRID_SIZE.x,(float)GRID_SIZE.y / 2} + squarePos ,
							vf2d{(float)GRID_SIZE.x / 2,(float)GRID_SIZE.y} + squarePos ,
						}, { {0,0},{0,0} ,{0,0} ,{0,0} }, game->GetData(t.enemyId).col);
				}
				else {
					game->DrawDecal(squarePos, game->circle, { 1,1 }, {
						game->GetData(t.enemyId).col.r,
						game->GetData(t.enemyId).col.g,
						game->GetData(t.enemyId).col.b,
						(uint8_t)(waveLayer == 0 && t.wave1||waveLayer==1&&t.wave2||waveLayer==2&&t.wave3 ? 255 : 64)
						});
					if (t.enemyId >= START) {
						game->DrawRotatedDecal(squarePos + vf2d{ 16, 16 }, game->arrow, PI / 2 * (int)t.facingDir, { 16,16 }, { 1,1 }, {
							WHITE.r,
							WHITE.g,
							WHITE.b,
							(uint8_t)(waveLayer == 0 && t.wave1 || waveLayer == 1 && t.wave2 || waveLayer == 2 && t.wave3 ? 255 : 64)
							}
						);
					}
				}
			}
			game->DrawLineDecal(squarePos, { squarePos.x + (float)GRID_SIZE.x,squarePos.y }, t.wallN ? WHITE : Pixel{ 64,64,64 });
			game->DrawLineDecal({ squarePos.x + (float)GRID_SIZE.x,squarePos.y }, { squarePos.x + (float)GRID_SIZE.x,squarePos.y + (float)GRID_SIZE.y }, t.wallE ? WHITE : Pixel{ 64,64,64 });
			game->DrawLineDecal({ squarePos.x + (float)GRID_SIZE.x,squarePos.y + (float)GRID_SIZE.y }, { squarePos.x,squarePos.y + (float)GRID_SIZE.y }, t.wallS ? WHITE : Pixel{ 64,64,64 });
			game->DrawLineDecal({ squarePos.x,squarePos.y + (float)GRID_SIZE.y }, squarePos, t.wallW ? WHITE : Pixel{ 64,64,64 });
		}
	}
}

void Editor::WaveLayerSelection()
{
	if (!game->IsTextEntryEnabled()) {
		if (game->GetKey(K1).bPressed) {
			waveLayer = 0;
		}
		if (game->GetKey(K2).bPressed) {
			waveLayer = 1;
		}
		if (game->GetKey(K3).bPressed) {
			waveLayer = 2;
		}
	}
}

void Editor::SaveLevel()
{
	std::ofstream file("assets/map/map" + std::to_string(level) + ".map");
	file << MAP_SIZE.x << std::endl;
	file << MAP_SIZE.y << std::endl;
	for (int y = 0; y < MAP_SIZE.y; y++) {
		for (int x = 0; x < MAP_SIZE.x; x++) {
			int databits=0;
			Tile& t = map[y][x];
			databits =
				t.blink << 15 |
				int(t.facingDir) << 13 |
				int(t.enemyId) << 7 |
				t.wave3 << 6 |
				t.wave2 << 5 |
				t.wave1 << 4 |
				t.wallN << 3 |
				t.wallE << 2 |
				t.wallS << 1 |
				t.wallW;
			file << databits << std::endl;
		}
	}
	file.close();
}

void Editor::OnTextEntryComplete(const std::string& sText) {
	std::stringstream ss(game->TextEntryGetString());
	int input;
	ss >> input;
	switch (promptState) {
		case PromptState::ENTER_LEVEL: {
			if (input >= 1 && input <= 30) {
				game->TextEntryEnable(false);
				promptState = PromptState::NONE;
				this->level = input;
				map = LoadLevel(this->level);
				MAP_SIZE = { (int)map[0].size(),(int)map.size() };
			}
			else {
				reEnableTextEntry = true;
			}
		}break;
		case PromptState::ENTER_WIDTH: {
			if (input >= 1 && input <= 50) {
				promptState = PromptState::ENTER_HEIGHT;
				reEnableTextEntry = true;
				this->MAP_SIZE.x = input;
				if (MAP_SIZE.x == map[0].size()) {
					break; //We don't care to resize the vecetor at this point.
				}
				if (MAP_SIZE.x < map[0].size()) {
					for (int y = 0; y < map.size(); y++) {
						std::vector<Tile>& row = map[y];
						row.erase(row.begin() + MAP_SIZE.x, row.end());
					}
				}
				else {
					for (int y = 0; y < map.size(); y++) {
						std::vector<Tile>& row = map[y];
						for (int x = map[y].size(); x < MAP_SIZE.x; x++) {
							Tile t = {};
							if (x > 0) {
								Tile& neighborW = map[y][x-1];
								t.wallW = neighborW.wallE;
							}
							row.push_back(t);
						}
					}
				}
			}
			else {
				reEnableTextEntry = true;
			}
		}break;
		case PromptState::ENTER_HEIGHT: {
			if (input >= 1 && input <= 50) {
				game->TextEntryEnable(false);
				promptState = PromptState::NONE;
				this->MAP_SIZE.y = input;
				if (MAP_SIZE.y == map.size()) {
					break; //We don't care to resize the vecetor at this point.
				}
				if (MAP_SIZE.y < map.size()) {
					map.erase(map.begin() + MAP_SIZE.y, map.end());
				}
				else {
					for (int y = map.size(); y < MAP_SIZE.y; y++) {
						std::vector<Tile> row;
						for (int x = 0; x < MAP_SIZE.x; x++) {
							Tile t = {};
							if (y > 0) {
								Tile& neighborN = map[y - 1][x];
								t.wallN = neighborN.wallS;
							}
							row.push_back(t);
						}
						map.push_back(row);
					}
				}
			}
			else {
				reEnableTextEntry = true;
			}
		}break;
	}
	
}

std::vector<std::vector<Tile>> Editor::LoadLevel(int level) {
	std::vector<std::vector<Tile>> map;
	std::ifstream file("assets/map/map"+std::to_string(level)+".map");
	if (file.good()) {
		while (file.good()) {
			std::string line;
			std::getline(file, line);
			int width = std::atoi(line.c_str());
			std::getline(file, line);
			int height = std::atoi(line.c_str());
			vi2d MAP_SIZE = { width,height };
			map.clear();
			for (int y = 0; y < MAP_SIZE.y; y++) {
				std::vector<Tile>row;
				for (int x = 0; x < MAP_SIZE.x; x++) {
					std::getline(file, line);
					int map_data = std::atoi(line.c_str());
					Tile newTile;
					newTile.blink = (map_data & 0b1000000000000000) >> 15;
					newTile.facingDir = FacingDirection((map_data & 0b0110000000000000) >> 13);
					newTile.enemyId = EnemyID((map_data & 0b0001111110000000) >> 7);
					newTile.wave1 = (map_data & 0b10000) >> 4;
					newTile.wave2 = (map_data & 0b100000) >> 5;
					newTile.wave3 = (map_data & 0b1000000) >> 6;
					newTile.wallN = (map_data & 0b1000) >> 3;
					newTile.wallE = (map_data & 0b100) >> 2;
					newTile.wallS = (map_data & 0b10) >> 1;
					newTile.wallW = (map_data & 0b1);
					row.push_back(newTile);
				}
				map.push_back(row);
			}
			goto loopDone;
		}
		loopDone: 
		int a;
	}
	else {
		std::cout << "Map Level " << level << " does not exist. Creating default map."<<std::endl;
		vi2d MAP_SIZE = { 5,5 };
		map.clear();
		for (int y = 0; y < MAP_SIZE.y; y++) {
			std::vector<Tile>row;
			for (int x = 0; x < MAP_SIZE.x; x++) {
				row.push_back({});
			}
			map.push_back(row);
		}
	}
	return map;
}