#pragma once
#include "olcPixelGameEngine.h"
#include "Animation.h"
#include "State.h"
#include "Player.h"
#include "olcUTIL_Animate2D.h"

enum MonsterStrategy{
	RUN_TOWARDS,
	SHOOT_AFAR
};

enum MonsterName{
	SLIME_GREEN,
	SLIME_BLUE,
	SLIME_RED,
	SLIME_YELLOW,


	///////////////////////////////////////////////////////////////////////////////////////////////////////////
	/*//*/END,//Used for detecting the end of the list, DO NOT USE OR TOUCH. Add all monsters above this//*//*/
	///////////////////////////////////////////////////////////////////////////////////////////////////////////
};

struct MonsterData{
	private:
	int hp;
	int atk;
	float moveSpd;//1.0=100%
	float size;
	std::vector<AnimationState> animations;
	MonsterStrategy strategy;
	MonsterName type;
	int collisionDmg;
	AnimationState jumpAnimation=AnimationState::WARRIOR_IDLE_S;
	AnimationState shootAnimation=AnimationState::WARRIOR_IDLE_S;
	AnimationState deathAnimation=AnimationState::WARRIOR_IDLE_S;
	public:
	MonsterData();
	//When specifying animations, the first one will become the default animation. The last becomes the death animation.
	MonsterData(MonsterName type,int hp,int atk,std::vector<AnimationState>animations,AnimationState jumpAnimation,AnimationState shootAnimation,AnimationState deathAnimation,float moveSpd=1.0f,float size=1.0f,MonsterStrategy strategy=RUN_TOWARDS,int collisionDmg=0);
	int GetHealth();
	int GetAttack();
	float GetMoveSpdMult();
	float GetSizeMult();
	MonsterName GetType();
	MonsterStrategy GetAIStrategy();
	int GetCollisionDmg();
	AnimationState GetJumpAnimation();
	AnimationState GetShootAnimation();
	AnimationState GetDeathAnimation();
	std::vector<AnimationState>GetAnimations(){
		return animations;
	}
};

struct Monster{
	private:
	vf2d pos;
	vf2d vel={0,0};
	float friction=400;
	vf2d target={0,0};
	float targetAcquireTimer=0;
	int hp,maxhp;
	int atk;
	float moveSpd;
	float size;
	float attackCooldownTimer=0;
	float queueShotTimer=0;
	Key facingDirection;
	MonsterStrategy strategy;
	State state=State::NORMAL;
	Animate2D::Animation<AnimationState>animation;
	Animate2D::AnimationState internal_animState;
	float randomFrameOffset=0.f;
	float deathTimer=0.f;
	MonsterName type;
	std::vector<Buff>buffList;
	AnimationState GetDeathAnimationName();
	bool hasHitPlayer=false;
	bool canMove=true; //Set to false when stuck due to collisions.
	bool upperLevel=false;
protected:
	public:
	Monster()=delete;
	Monster(vf2d pos,MonsterData data);
	vf2d&GetPos();
	int GetHealth();
	int GetAttack();
	float GetMoveSpdMult();
	float GetSizeMult();
	Animate2D::Frame GetFrame();
	void UpdateAnimation(AnimationState state);
	bool Update(float fElapsedTime);
	//Returns true when damage is actually dealt (there is a death check here.)
	bool Hurt(int damage);
	bool IsAlive();
	vf2d&GetTargetPos();
	Key GetFacingDirection();
	void Draw();
	void Collision(Player&p);
	void Collision(Monster&p);
	void Collision();
	void SetVelocity(vf2d vel);
	//Returns false if the monster could not be moved to the requested location due to collision.
	bool SetPosition(vf2d pos);
	//Returns false if the monster could not be moved to the requested location due to collision.
	bool SetX(float x);
	//Returns false if the monster could not be moved to the requested location due to collision.
	bool SetY(float y);
	void PerformJumpAnimation();
	void PerformShootAnimation();
	bool OnUpperLevel();
	void Moved();

	void AddBuff(BuffType type,float duration,float intensity);
	std::vector<Buff>GetBuffs(BuffType buff);
};

struct MonsterSpawner{
	private:
	vf2d pos;
	vf2d range;
	std::vector<std::pair<MonsterName,vf2d>>monsters;
	bool triggered=false;
	public:
	MonsterSpawner();
	//For the monster list, the second pair item is the position relative to the spawner to spawn the monster.
	MonsterSpawner(vf2d pos,vf2d range,std::vector<std::pair<MonsterName,vf2d>>MONSTER_LIST);
	bool SpawnTriggered();
	vf2d GetRange();
	vf2d GetPos();
	void SetTriggered(bool trigger,bool spawnMonsters=true);
	friend std::ostream&operator<<(std::ostream&os,MonsterSpawner&rhs);
};