#include "Level3.h"
#include "CustomAudioManager.h"
#include "GameManager.h"
#include "HealthParticle.h"
#include "PlayerUpgradeParticle2.h"
#include "PlayerUpgradeParticle.h"
#include "HeightEnemy.h"
#include "MediumEnemy.h"



USING_NS_CC;

Scene* Level3::createScene()
{
	auto scene = Scene::create();
	auto layer = Level3::create();
	scene->addChild(layer);
	return scene;
}

bool Level3::init()
{
	if (!BaseGameLayer::init())
	{
		return false;
	}


	initializeVariables();
	initActors();
	scheduleActions();
	return true;
}


void Level3::scheduleActions(){
	awakeMediumEnemyScheduler();

	//comienza el bucle del juego
	this->schedule(schedule_selector(Level3::update));
	schduleUpgrades();
}

void Level3::schduleUpgrades(){
	//heath & upgrade launchers
	DelayTime *delayOne = DelayTime::create(60);
	DelayTime *delayTwo = DelayTime::create(30);
	CallFunc *launhHealth = CallFunc::create(CC_CALLBACK_0(Level3::launchHealth, this));
	CallFunc *launchUpgrade = CallFunc::create(CC_CALLBACK_0(Level3::launchUpgrade, this));
	auto upgrade = RepeatForever::create(Sequence::create(delayTwo, launchUpgrade, NULL));
	upgrade->setTag(Upgrade);
	runAction(RepeatForever::create(Sequence::create(delayOne, launhHealth, NULL)));
	runAction(upgrade);
}

void Level3::initActors()
{
	//50 enemigos en total
	//del 0 al 15 seran basicos
	_numEnemies = 45;_enemyIndex = 0;
	//15 enemigos medios
	//del 15 al 30 medios
	_numMediumEnemies = 15;	
	//15 enemigos nivel alto
	//del 30 al 45 seran de nivel alto
	_numHeightEnemies = 15; _heightEnemyIndex = _mediumEnemyIndex + _numMediumEnemies;
	
	//inserta los enemigos basicos al array de enemigos
	for (int i = 0; i < _numEnemies - _numMediumEnemies-_numHeightEnemies; i++){
		auto enemy = BasicEnemy::create();
		enemy->setTarget(_player);
		_enemyPool.pushBack(enemy);
		_gameBatchNode->addChild(enemy, ForegroundPos);
	}
	//inserta los enemigos de nivel medio al array
	for (int i = 0; i < _numMediumEnemies; i++){
		auto enemy = MediumEnemy::create();
		enemy->setTarget(_player);
		_enemyPool.pushBack(enemy);
		_gameBatchNode->addChild(enemy, ForegroundPos);
	}
	//inserta los enemigos de nivel alto al array
	for (int i = 0; i < _numHeightEnemies; i++){
		auto enemy = HeightEnemy::create();
		enemy->setTarget(_player);
		_enemyPool.pushBack(enemy);
		_gameBatchNode->addChild(enemy, ForegroundPos);
	}
	//hacer que el jugador sepa acerca de los enemigos
	_player->setTargets(_enemyPool);
}

void Level3::initializeVariables(){
	CustomAudioManager::getInstance()->playBackgroundSound("music/Spectre.wav", true);
	setTag(3);//level3
	_scoreToCompleTheLevel = 2000;
	_bg = new Background("fondo");
	_bg->setParent(_gameBatchNode, BackgroundPos);
	_mediumAwakeSpeed = 1.5f;
	_heightAwakeSpeed = 2.0f;

	//flag para saber si estan los enemigos de nivel medio en escena
	//y parar el scheduler de enemigos basicos
	_heightSchedulerRunning = false;

	_health = HealthParticle::create();
	_health->setTarget(_player);
	addChild(_health, ForegroundPos);

	_upgrade = PlayerUpgradeParticle::create();
	_upgrade->setTarget(_player);
	addChild(_upgrade, ForegroundPos);

	_upgrade2 = PlayerUpgradeParticle2::create();
	_upgrade2->setTarget(_player);
	addChild(_upgrade2, ForegroundPos);
}




void Level3::update(float dt)
{
	BaseGameLayer::update(dt);
	_player->update(dt);
	//check for collision between enemies & player
	checkCollisions();
	launchHeightEnemies();
}

void Level3::respawnButtonAction()
{
	BaseGameLayer::respawnButtonAction();
	_health->setVisible(false);
	_upgrade->setVisible(false);
	_upgrade2->setVisible(false);
	_heightSchedulerRunning = false;

	stopAllActions();
	scheduleActions();

	for (int i = 0; i < _numEnemies; i++){
		_enemyPool.at(i)->reset();
	}
}

void Level3::pauseButtonAction()
{
	BaseGameLayer::pauseButtonAction();
	_player->pause();
	_health->pause();
	_upgrade->pause();
	_upgrade2->pause();
	for (Sprite* enemy : _enemyPool){
		enemy->pause();
	}
}

void Level3::playButtonAction()
{
	BaseGameLayer::playButtonAction();
	_player->resume();
	_health->resume();
	_upgrade->resume();
	_upgrade2->resume();
	for (Sprite* enemy : _enemyPool){
		enemy->resume();
	}
}




void Level3::awakeMediumEnemyScheduler()
{

	DelayTime *delayAction = DelayTime::create(_mediumAwakeSpeed);
	CallFunc *callSelectorAction = CallFunc::create(CC_CALLBACK_0(Level3::awakeMediumEnemy, this));
	auto awakeEnemySequence = Sequence::create(delayAction, callSelectorAction, NULL);
	auto action = RepeatForever::create(awakeEnemySequence);
	action->setTag(MediumScheduler);

	runAction(action);
}

void Level3::awakeMediumEnemy()
{
	//despierta un enemigo basico que sigue a un enemigo medio.
	_enemyIndex = _enemyIndex % (_numEnemies - _numMediumEnemies-_numHeightEnemies);

	//basic enemy
	auto basicEnemy = _enemyPool.at(_enemyIndex);
	auto size = basicEnemy->getBoundingBox().size;
	//Positioning
	basicEnemy->setPositionX(RandomHelper::random_int(static_cast(size.width * 0.5),
		static_cast(_visibleSize.width - size.width * 0.5)));
	basicEnemy->setPositionY(_visibleSize.height + size.height * 1.5);
	basicEnemy->setCurrentAnimation(BasicEnemy::Animations::IDLE);
	//awake
	if (!basicEnemy->isVisible()){
		basicEnemy->setVisible(true);
	}

	//medium enemy
	auto enemy = _enemyPool.at(_mediumEnemyIndex+_enemyIndex);
	//Positioning
	enemy->setPositionX(basicEnemy->getPositionX());
	enemy->setPositionY(basicEnemy->getPositionY() - size.height);
	enemy->setCurrentAnimation(BasicEnemy::Animations::IDLE);
	//awake
	if (!enemy->isVisible()){
		enemy->setVisible(true);
	}

	_enemyIndex++;
}

void Level3::awakeHeightEnemy()
{
	//indice entre 0 y 15, suma el offset correspondiente al tipo de enemigo,
	//para ellos tenemos 15, 15 y 15 enemigos de cada tipo
	_enemyIndex = _enemyIndex % (_numEnemies - _numMediumEnemies - _numHeightEnemies);

	//medium enemy
	auto mediumEnemy = _enemyPool.at(_enemyIndex + _numMediumEnemies);
	auto mediumEnemySize = mediumEnemy->getBoundingBox().size;
	//Positioning
	mediumEnemy->setPositionX(RandomHelper::random_int(static_cast(mediumEnemySize.width * 0.5),
		static_cast(_visibleSize.width - mediumEnemySize.width * 0.5)));
	mediumEnemy->setPositionY(_visibleSize.height + mediumEnemySize.height * 1.5);
	mediumEnemy->setCurrentAnimation(BasicEnemy::Animations::IDLE);
	//awake
	if (!mediumEnemy->isVisible()){
		mediumEnemy->setVisible(true);
	}

	//height enemy
	auto heightEnemy = _enemyPool.at(_numHeightEnemies + _numMediumEnemies + _enemyIndex);
	auto heightEnemySize = heightEnemy->getBoundingBox().size;
	//Positioning
	heightEnemy->setPositionX(RandomHelper::random_int(static_cast(heightEnemySize.width * 0.5),
		static_cast(_visibleSize.width - heightEnemySize.width * 0.5)));
	heightEnemy->setPositionY(mediumEnemy->getPositionY() - mediumEnemySize.height);
	heightEnemy->setCurrentAnimation(BasicEnemy::Animations::IDLE);
	//awake
	if (!heightEnemy->isVisible()){
		heightEnemy->setVisible(true);
	}

	_enemyIndex++;
}

void Level3::awakeHeightEnemyScheduler()
{

	DelayTime *delayAction = DelayTime::create(_heightAwakeSpeed);
	CallFunc *callSelectorAction = CallFunc::create(CC_CALLBACK_0(Level3::awakeHeightEnemy, this));
	auto awakeEnemySequence = Sequence::create(delayAction, callSelectorAction, NULL);
	auto action = RepeatForever::create(awakeEnemySequence);
	action->setTag(HeightScheduler);
	runAction(action);
	
}




void Level3::checkCollisions()
{
	for (int i = 0; i < _numEnemies; i++){
		auto enemy = _enemyPool.at(i);
		if (_player->getBoundingBox().intersectsRect(enemy->getBoundingBox())
			&& enemy->isVisible() && _player->isVisible()){
			enemy->setCurrentAnimation(BasicEnemy::Animations::EXPLOSION);
			_player->setHealth(0);
		}
	}
}

void Level3::launchHealth(){

	auto width = _health->getBoundingBox().size.width;
	auto height = _health->getBoundingBox().size.height;
	_health->setAnchorPoint(Point(0.5f, 0.5f));
	_health->setPositionX(RandomHelper::random_int(static_cast(0 + width * 0.5),
		static_cast(_visibleSize.width - width * 0.5)));
	_health->setPositionY(_visibleSize.height *1.3);
	_health->setVisible(true);

}

void Level3::launchUpgrade(){
	auto width = _upgrade->getBoundingBox().size.width;
	auto height = _upgrade->getBoundingBox().size.height;
	_upgrade->setAnchorPoint(Point(0.5f, 0.5f));
	_upgrade->setPositionX(RandomHelper::random_int(static_cast(0 + width * 0.5),
		static_cast(_visibleSize.width - width * 0.5)));
	_upgrade->setPositionY(_visibleSize.height *1.3);
	_upgrade->setVisible(true);
}

void Level3::launchUpgrade2(){
	auto width = _upgrade2->getBoundingBox().size.width;
	auto height = _upgrade2->getBoundingBox().size.height;
	_upgrade2->setAnchorPoint(Point(0.5f, 0.5f));
	_upgrade2->setPositionX(RandomHelper::random_int(static_cast(0 + width * 0.5),
		static_cast(_visibleSize.width - width * 0.5)));
	_upgrade2->setPositionY(_visibleSize.height *1.3);
	_upgrade2->setVisible(true);
}

void Level3::launchHeightEnemies(){
	if (!_heightSchedulerRunning && GameManager::getInstance()->getPlayerScore() >= 700){
		awakeHeightEnemyScheduler();
		stopActionByTag(MediumScheduler);
		stopActionByTag(Upgrade);

		//tira el upgrade
		DelayTime *delayAction = DelayTime::create(8.0f);
		CallFunc *callSelectorAction = CallFunc::create(CC_CALLBACK_0(Level3::launchUpgrade2, this));
		auto launchUpgrade2 = Sequence::create(delayAction, callSelectorAction, NULL);
		runAction(launchUpgrade2);

		DelayTime *delayOne = DelayTime::create(68);
		
		runAction(RepeatForever::create(Sequence::create(delayOne, callSelectorAction, NULL)));
		_heightSchedulerRunning = true;
	}
}