#pragma once
#include <fstream> // ifstream & ofstream !! FOR DEBUG
#include <time.h>
#include <math.h>
#include "QTable.h"
#include "FleeManager.h"
#include "ExploreManager.h"

// Rewards
#define WIN 100
#define LOSE -100
#define ALIVE -0.01
#define ENEMYDESTROYED 50
#define UNITLOST -20
#define UNITDAMAGED -5

#define MAXFOLLOW 12 // Maximum number of frames that we allow our unit to chase an enemy target

class QAgent
{
	FleeManager fleeMgr;
	ExploreManager expMgr;
	
	BWAPI::Unit unit;
	int id, killCounter, lastHP;
	QTable *qTable;

	double accumulatedReward;
	State currentState, nextState;
	int currentAction;
	int followCounter; // How many frames has the unit followed an enemy target

public:
	QAgent(BWAPI::Unit u, QTable *qTable);
	// Getters
	BWAPI::Unit getUnit();
	int getID();
	double getAccumulatedReward();
	QTable getQTable();
	State getCurrentState();
	int getCurrentAction();
	bool isAttacking();
	int getFollowCounter();
	// Setters
	void setQTable(QTable qt);
	void setWeights(std::vector<double> w);

	void init();
	int step(bool isFinalState, bool isWinner);
	void updateQValue(State state, int action, State nextState, double reward, bool terminalState);
	void updateWeights(State state, int action, State nextState, double reward, bool terminalState);
	State getState(BWAPI::Unit u);
	int getAction(State state, BWAPI::Unit unit); // Returns the next action to perform from a given state.
	int getPolicy(State state, BWAPI::Unit unit); // Returns the best action to perform from a given state in terms of expected reward.
	int getRandomAction(State state, BWAPI::Unit unit); // Returns a random action from all the actions that can be performed from a given state.
	void performAction(int action, BWAPI::Unit unit); // Takes the action
	int getInstantReward(bool isWinner);
	// Actions
	void attack(BWAPI::Unit unit);
	void flee(BWAPI::Unit unit);
	std::set<Block*> getFleeGrid();
	Block* getFleeBlock();
	void defend(BWAPI::Unit unit);
	void explore(BWAPI::Unit unit);
	void carryOn();

	bool operator<(const QAgent &qAgent) const;
};