package com.pesets.game;

import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.math.MathUtils;
import com.pesets.game.skills.Skill;

public class Enemy extends GameObject {
	public static float RespawnTimeMin = 30;
	public static float RespawnTimeMax = 45;
	public static float MoveFreqMin = 1;
	public static float MoveFreqMax = 4;
	
	private int type;
	private ShapeRenderer renderer = new ShapeRenderer();
	private float spawnX, spawnY;
	private float timeToRespawn;
	private float timeToMove;
	private FourWaySprite sprite;
	
	private GameObject target = null;

	public Enemy(IGameObjectCallback callback, int type, int level, float spawnX, float spawnY) {
		super(callback);
		this.type = type;
		this.level = level;
		this.spawnX = spawnX;
		this.spawnY = spawnY;
		
		strength += level * (2 + level / 10);
		agility += level * (1 + level / 8);
		stamina += level * (2 + level / 10);
		intelligence += level * (1 + level / 10);

		switch (type)
		{
		case 1:
			sprite = new FourWaySprite("enemy2.png", 48, 64);
			break;
		case 3:
			sprite = new FourWaySprite("enemy3.png", 75, 64);
			break;
		case 2:
			sprite = new FourWaySprite("enemy4.png", 32, 48);
			break;	
		case 4:
			sprite = new FourWaySprite("enemy5.png", 64, 64);
			break;	
		case 6:
			sprite = new FourWaySprite("enemy6.png", 80, 80);
			break;
		case 5:
			sprite = new FourWaySprite("enemy7.png", 80, 80);
			break;
		case 7:
			sprite = new FourWaySprite("enemy8.png", 96, 96);
			break;
		default:
			sprite = new FourWaySprite("enemy1.png", 32, 48);
		}
		respawn();
		width = sprite.width;
		height = sprite.height;
	}

	@Override
	public void render(SpriteBatch batch) {
		super.render(batch);
		if (isDead()) return;
		sprite.draw(batch, 1);
	}

	@Override
	public void update(float dt) {
		super.update(dt);
		sprite.setPos(x, y);
		
		if (isDead())
		{
			timeToRespawn -= dt;
			if (timeToRespawn <= 0)
			{
				respawn();
			}
			return;
		}
		
		for (int i = 0; i < effects.length; i++)
		{
			if (effects[i] > 0)
				effects[i] -= dt;
		}
		
		if (effects[Skill.EffectStun] > 0)
		{
			return;
		}
		if (effects[Skill.EffectSlow] > 0)
		{
			dt *= 0.75f;
		}
		
		if (target != null && target.isDead() == false)
		{
			if (target.dist2(this) <= Map.CellSize * Map.CellSize)
			{
				state = ObjectState.Attack;
				if (attackCD <= 0)
				{
					target.hit(this);
					attackCD += getAttackColdown();
				}
				else
				{
					attackCD -= dt;
				}
				
				if (target.isDead()) resetTarget();
				return;
			}
				

			state = ObjectState.Moving;
			
			if (path.isEmpty())
			{
				int x1 = (int)(x / Map.CellSize);
				int y1 = (int)(y / Map.CellSize);
				int x2 = (int)(target.x / Map.CellSize);
				int y2 = (int)(target.y / Map.CellSize);
				
				path = callback.getPassage().findPath(x1, y1, x2, y2);
				return;
			}
			
			return;
		}
		
		if (path.isEmpty() == false)
		{
			sprite.update(dt * 1.5f);
			sprite.setDirectionToPos(path.getFirst());
		}
		
		timeToMove -= dt;
		
		if (timeToMove <= 0)
		{
			timeToMove += MathUtils.random(MoveFreqMin, MoveFreqMax);
			int dx = 0, dy = 0;
			int x1 = (int)(x / Map.CellSize);
			int y1 = (int)(y / Map.CellSize);
			int iterations = 0;
			do
			{
				iterations++;
				int choice = MathUtils.random(3);
				dx = 0; dy = 0;
				switch (choice)
				{
				case 0:
					dx--; break;
				case 1:
					dx++; break;
				case 2:
					dy--; break;
				case 3:
					dy++; break;
				}
				if (iterations > 10) break;
			}
			while (callback.getPassage().isCanPass(x1 + dx, y1 + dy) == false);
			path.add(callback.getPassage().getRealCoords(x1 + dx, y1 + dy));
		}
	}

	private void respawn() {
		x = spawnX;
		y = spawnY;
		hp = getMaxHP();
		attackCD = getAttackColdown();
		
		timeToMove = MathUtils.random(MoveFreqMin, MoveFreqMax);
		state = ObjectState.Moving;
		path.clear();
		target = null;
		for (int i = 0; i < effects.length; i++)
		{
			effects[i] = 0;
		}
	}
	
	public void resetTarget()
	{
		target = null;
		path.clear();
		timeToMove = MathUtils.random(MoveFreqMin, MoveFreqMax);
		state = ObjectState.Moving;
	}

	@Override
	public void hit(GameObject obj) {
		float oldhp = hp;
		super.hit(obj);

		PlayerStatistics.getInstance().damageDealt += oldhp - hp;
		
		if (isDead())
		{
			timeToRespawn = MathUtils.random(RespawnTimeMin, RespawnTimeMax);
		}
		
		aggro(obj);
	}
	
	public void skillHit(GameObject obj, int damage, int effect, float duration)
	{

		PlayerStatistics.getInstance().damageBySkills += damage;
		PlayerStatistics.getInstance().damageDealt += damage;
		hp -= damage;
		if (hp < 0) hp = 0;
		
		if (duration > 0)
		{
			effects[effect] = Math.max(effects[effect], duration);
		}
				
		if (isDead())
		{
			timeToRespawn = MathUtils.random(RespawnTimeMin, RespawnTimeMax);
		}
		
		aggro(obj);
	}
	
	public void aggro(GameObject obj)
	{
		target = obj;
		sprite.setDirectionToPos(obj.x, obj.y);
	}

	public int getLevel()
	{
		return level;
	}

	
	public int getExpForKill()
	{
		return level * 10;
	}
}
