#include "CombatSimulation.h"
#include "UnitUtil.h"
#include "FAP.h"

using namespace UAlbertaBot;
using namespace BWAPI;

CombatSimulation::CombatSimulation()
{
}

// sets the starting states based on the combat units within a radius of a given position
// this center will most likely be the position of the forwardmost combat unit we control
int CombatSimulation::simulateCombatFAP(const BWAPI::Position & center, const int radius, bool canAttackGround, bool canAttackAir)
{
	fap.clearState();

	if (Config::Debug::DrawCombatSimulationInfo)
	{
		BWAPI::Broodwar->drawCircleMap(center.x, center.y, 6, BWAPI::Colors::Red, true);
		BWAPI::Broodwar->drawCircleMap(center.x, center.y, radius, BWAPI::Colors::Red);
	}


	//Our units
	BWAPI::Unitset ourCombatUnits;
	MapGrid::Instance().GetUnits(ourCombatUnits, center, radius, true, false);

	for (auto & unit : ourCombatUnits)
	{
		// Exclude workers and buildings (and static defense)
		if (unit->getType().isWorker() || unit->getType().isBuilding())
		{
			continue;
		}

		if (UnitUtil::IsCombatSimUnit(unit))
		{
			fap.addIfCombatUnitPlayer1(unit);
			if (Config::Debug::DrawCombatSimulationInfo)
			{
				BWAPI::Broodwar->drawCircleMap(unit->getPosition(), 3, BWAPI::Colors::Green, true);
			}
		}
	}


	//Enemy units
	std::vector<UnitInfo> enemyCombatUnits;
	InformationManager::Instance().getNearbyForce(enemyCombatUnits, center, BWAPI::Broodwar->enemy(), radius);

	for (UnitInfo & ui : enemyCombatUnits)
	{
		// if unit is flying, skip it if we can not attack it
		if (ui.type.isFlyer() && !canAttackAir && canAttackGround)
		{
			continue;
		}

		// The check is careful about seen units and assumes that unseen units are completed and powered.
		if (ui.lastHealth > 0 &&
			(ui.unit->exists() || (ui.lastPosition.isValid() && !ui.goneFromLastPosition)) &&
			(ui.unit->exists() ? UnitUtil::IsCombatSimUnit(ui.unit) : UnitUtil::IsCombatSimUnit(ui.type)))
		{
			fap.addIfCombatUnitPlayer2(ui);
			if (Config::Debug::DrawCombatSimulationInfo)
			{
				BWAPI::Broodwar->drawCircleMap(ui.lastPosition, 3, BWAPI::Colors::Red, true);
			}
		}
	}


	//pre sim scores
	std::pair<int, int> initScore = fap.playerScores();
	std::pair<int, int> initUnitcount = { (int)fap.getState().first->size(), (int)fap.getState().second->size() };

	//short sim
	fap.simulate(24 * 4);

	//short sim scores
	std::pair<int, int> shortScore = fap.playerScores();
	std::pair<int, int> shortUnitcount = { (int)fap.getState().first->size(), (int)fap.getState().second->size() };
	/*
	//long sim
	fap.simulate(24 * 26);

	//long sim scores
	std::pair<int, int> longScore = fap.playerScores();
	std::pair<int, int> longUnitcount = { (int)fap.getState().first->size(), (int)fap.getState().second->size() };
	*/

	//get result (my score - enemy score)
	int resultShort1 = shortScore.first - shortScore.second;
	//int resultLong1 = longScore.first - longScore.second;

	//get result (enemy loss - my loss)
	int resultShort2 = (initScore.second - shortScore.second) - (initScore.first - shortScore.first);
	//int resultLong2 = (initScore.second - longScore.second) - (initScore.first - longScore.first);


	std::string simtype = "";
	std::pair<int, int> score;
	std::pair<int, int> unitcount;
	int result = -1;
	
	if (initScore.first > 1.667 * initScore.second)
	{
		simtype = "Short1";
		result = resultShort1;
		score = shortScore;
		unitcount = shortUnitcount;
		/*
		if (resultLong1 > resultShort1) {
			simtype = "Long1";
			result = resultLong1;
			score = longScore;
			unitcount = longUnitcount;
		}
		*/
	}
	else
	{
		simtype = "Short2";
		result = resultShort2;
		score = shortScore;
		unitcount = shortUnitcount;
		/*
		if (resultLong2 > resultShort2) {
			simtype = "Long2";
			result = resultLong2;
			score = longScore;
			unitcount = longUnitcount;
		}
		*/
	}

	if (Config::Debug::DrawCombatSimulationInfo)
	{
		std::stringstream ss1;
		ss1 << "Initial score: " << initScore.first << " : " << initScore.second << "\n";
		ss1 << "P1: " << initUnitcount.first << "\n";
		ss1 << "P2: " << initUnitcount.second;

		std::stringstream ss2;
		ss2 << "Sim score: " << score.first << " : " << score.second << " (" << simtype.c_str() << ")\n";
		ss2 << "P1: " << unitcount.first << "\n";
		ss2 << "P2: " << unitcount.second;

		BWAPI::Broodwar->drawTextScreen(150, 200, "%s", ss1.str().c_str());
		BWAPI::Broodwar->drawTextScreen(300, 200, "%s", ss2.str().c_str());

		std::string prefix = result < 0 ? "\x06" : "\x07";
		BWAPI::Broodwar->drawTextScreen(240, 240, "Combat Sim: %s%d", prefix.c_str(), result);
	}

	return result;
}

