package entities;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.audio.Sound;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Animation;
import com.badlogic.gdx.graphics.g2d.Animation.PlayMode;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.Array;
import com.ld52.agent.Agent;

import java.util.HashMap;
import java.util.Iterator;
import java.util.UUID;

import Global.Global;
import u.UsefulMethods;

public class Worker extends Sprite {
	public enum State {
		WALKLEFT, WALKRIGHT, HOLDLEFT, HOLDRIGHT, DYING
	}

	private final int SEEKTIME = MathUtils.random(70, 250);
	private final int REALSEEKTIME = MathUtils.random(270, 450);
	private final int CANHITTIMERMAX = MathUtils.random(500, 800);
	private final int REFRESHTIMERMAX = MathUtils.random(200, 300);

	public State currentState;
	public State previousState;

	private Animation<TextureRegion> walkLeft;
	private Animation<TextureRegion> walkRight;
	private Animation<TextureRegion> holdLeft;
	private Animation<TextureRegion> holdRight;
	private Animation<TextureRegion> dying;
	private Texture t1;
	public Color color;
	public Rectangle rect;
	public boolean isMain = true;// start with main
	public boolean isDead = false;// move off screen.
	public int _isDeadTimer;
	private int _sw;// sprite width
	private int _sh;// sprite height
	private float speed;
	public Vector2 sp = new Vector2(0, 0);
	public Vector2 ep = new Vector2(0, 0);
	private Vector2 dir = new Vector2(0, 0);
	public boolean isWait = true;
	public boolean getDir;
	public boolean isCollidingWithHamsterWheel;
	public boolean isCollidingWithPlayer;
	public boolean isCollidingWithCore;
	public boolean isCollidingWithTurret;
	public boolean isCollidingWithBall;
	private float _stateTimer;
	private boolean isAnimationOver;
	public boolean isDying;
	private boolean l;
	private boolean r;
	private boolean u;
	private boolean d;
	public boolean canHit = true;
	public int canHitTimer = CANHITTIMERMAX;
	public boolean refreshed = true;
	public int refreshTimer = REFRESHTIMERMAX;
	private int fallUpTimer;
	private Sound death;// implement later
	public int isDyingTimer = 50;
	public boolean playOnce;
	private float aSpd = .2f;
	private float targetX;
	private float targetY;

	public boolean isHolding;

	public UUID uuid = UUID.randomUUID();
	private String isCollidingWithKitten;
	private String isCollidingWithPlant;
	private String isCollidingWithPerson;
	private String isCollidingWithHarvester;
	private int walkTimer;
	private int walkTimerMax = 20;

	public Worker(int _x, int _y) {
		rect = new Rectangle();
		rect.x = _x;
		rect.y = _y;
		rect.width = 32;
		rect.height = 32;

		_sw = 32;
		_sh = 32;

		// this is for the animations
		currentState = State.WALKRIGHT;
		previousState = State.WALKRIGHT;
		_stateTimer = 0f;
		// declare all the static frames (static states (no animation))
		t1 = new Texture(Gdx.files.internal("worker.png"));
		death = Gdx.audio.newSound(Gdx.files.internal("sfx/death.ogg"));
		// region hello
		speed = MathUtils.random(50f, 200f);// for now
		Array<TextureRegion> frames = new Array<TextureRegion>();
		frames.add(new TextureRegion(t1, (0 * _sw), (0 * _sh), _sw, _sh));
		frames.add(new TextureRegion(t1, (2 * _sw), (0 * _sh), _sw, _sh));
		walkLeft = new Animation<TextureRegion>(aSpd, frames, PlayMode.LOOP);
		frames.clear();
		frames.add(new TextureRegion(t1, (1 * _sw), (0 * _sh), _sw, _sh));
		frames.add(new TextureRegion(t1, (3 * _sw), (0 * _sh), _sw, _sh));
		walkRight = new Animation<TextureRegion>(aSpd, frames, PlayMode.LOOP);
		frames.clear();
		frames.add(new TextureRegion(t1, (4 * _sw), (0 * _sh), _sw, _sh));
		frames.add(new TextureRegion(t1, (6 * _sw), (0 * _sh), _sw, _sh));
		holdLeft = new Animation<TextureRegion>(aSpd, frames, PlayMode.LOOP);
		frames.clear();
		frames.add(new TextureRegion(t1, (5 * _sw), (0 * _sh), _sw, _sh));
		frames.add(new TextureRegion(t1, (7 * _sw), (0 * _sh), _sw, _sh));
		holdRight = new Animation<TextureRegion>(aSpd, frames, PlayMode.LOOP);
		frames.clear();
		frames.add(new TextureRegion(t1, (0 * _sw), (0 * _sh), _sw, _sh));
		frames.add(new TextureRegion(t1, (1 * _sw), (0 * _sh), _sw, _sh));
		frames.add(new TextureRegion(t1, (2 * _sw), (0 * _sh), _sw, _sh));
		frames.add(new TextureRegion(t1, (3 * _sw), (0 * _sh), _sw, _sh));
		frames.add(new TextureRegion(t1, (4 * _sw), (0 * _sh), _sw, _sh));
		frames.add(new TextureRegion(t1, (5 * _sw), (0 * _sh), _sw, _sh));
		frames.add(new TextureRegion(t1, (6 * _sw), (0 * _sh), _sw, _sh));
		frames.add(new TextureRegion(t1, (7 * _sw), (0 * _sh), _sw, _sh));
		dying = new Animation<TextureRegion>(aSpd, frames, PlayMode.LOOP);
		frames.clear();
		// assign random color
		color = new Color(new Color(MathUtils.random(.2f, 1f), MathUtils.random(.2f, 1f), MathUtils.random(.2f, 1f), 1));
		// color = Color.WHITE;
		setBounds(0, 0, _sw, _sh);
		setOriginCenter();
		setRegion(walkRight.getKeyFrame(_stateTimer, true));
	}

	public Vector2 GetDirection(Vector2 sp, Vector2 ep) {
		return ep.sub(sp).nor();
	}

	public void Update(float dt, Array<Plant> plants, Array<Person> peoples, Array<Kitten> kittens, Harvester harvester) {
		if (isDying && isDyingTimer > 0) {
			if (!Global.SetVolumeToZero && !playOnce) {
				playOnce = true;
				death.play(1f);
			}
			isDyingTimer--;
		} else {
			if (isDying && isDyingTimer <= 0)
				isDead = true;
			if (isDead) {
				rect.x = MathUtils.random(-400, 400);
				rect.y = MathUtils.random(-400, 400);
				playOnce = false;
			} else {
				if (walkTimer <= 0) {
					walkTimer = walkTimerMax;
					sp = new Vector2(rect.x, rect.y);
					if (!isHolding) {// go towards the closest plant people or kitten
						getClosestEnemy(plants, peoples, kittens, harvester);
						ep = new Vector2(targetX, targetY);
						dir = GetDirection(sp, ep);
					} else {// go to the harvester
						// System.out.println("harvesterX: " + harvester.rect.x + "harveseterY: " + harvester.rect.y);
						// System.out.println("rectX: " + rect.x + "rectY: " + rect.y);
						ep = new Vector2(harvester.rect.x, harvester.rect.y + MathUtils.random(100, 200));
						// System.out.println("sp: " + sp + "ep: " + ep);
						dir = GetDirection(sp, ep);
					}
				}
				if (walkTimer > 0)
					walkTimer--;
				// System.out.println("sp: " + sp + "ep: " + ep);
				rect.x += dir.x * speed * dt;
				rect.y += dir.y * speed * dt;
			}
		}
		getCorrectWalkingAnimation(dt);
//		System.out.println("isDead: " + isDead);
//		System.out.println("getDir: " + getDir);
//		System.out.println("SEEKTIME: " + SEEKTIME);
//		System.out.println("seeking: " + seekTimer);
//		System.out.println("REALSEEKTIME: " + REALSEEKTIME);
//		System.out.println("getRealDirectionTimer: " + getRealDirectionTimer);
//		System.out.println("REFRESHTIMERMAX: " + REFRESHTIMERMAX);
//		System.out.println("refreshTimer: " + refreshTimer);
//		System.out.println("CANHITTIMERMAX: " + CANHITTIMERMAX);
//		System.out.println("canHitTimer: " + canHitTimer);
//		System.out.println("canHit: " + canHit);
//		System.out.println("isCollidingWithPlayer: " + isCollidingWithPlayer);
//		System.out.println("isCollidingWithKitten: " + isCollidingWithKitten);
//		System.out.println("isCollidingWithPlant: " + isCollidingWithPlant);
//		System.out.println("isCollidingWithBall: " + isCollidingWithBall);
//		System.out.println("isCollidingWithPerson: " + isCollidingWithPerson);
//		System.out.println("isCollidingWithHarvester: " + isCollidingWithHarvester);
//		System.out.println("x: " + rect.x + " y: " + rect.y);

	}// end of update
		// if I have to, i'll have them both go to and shoot at the core. Shooting at the closest item is complicated because of managing all the separate
		// lists.

	/**
	 * @weasels the array of weasels
	 */
	private Vector2 getClosestEnemy(Array<Plant> plants, Array<Person> peoples, Array<Kitten> kittens, Harvester harvester) {
		float closestDistance = 1000000;
		Vector2 _sp = new Vector2(rect.x, rect.y);// starting point is always this initial 'living point'.
		Vector2 _ep = new Vector2(ep.x, ep.y);// we don't actually know this. This is what we are determining.
		HashMap<Float, Vector2> _distances = new HashMap<Float, Vector2>();
		for (Iterator<Plant> iter2 = plants.iterator(); iter2.hasNext();) {
			Plant w = iter2.next();
			ep = new Vector2(w.rect.x, w.rect.y);
			float dist = UsefulMethods.GetDistance(_sp, ep);
			if (dist < closestDistance && !w.isCarried && !w.isDead) {
				closestDistance = dist;
				_ep = ep;
			}
			_distances.put(closestDistance, _ep);
		}
		for (Iterator<Person> iter2 = peoples.iterator(); iter2.hasNext();) {
			Person w = iter2.next();
			ep = new Vector2(w.rect.x, w.rect.y);
			float dist = UsefulMethods.GetDistance(_sp, ep);
			if (dist < closestDistance && !w.isCarried && !w.isDead) {
				closestDistance = dist;
				_ep = ep;
			}
			_distances.put(closestDistance, _ep);
		}
		for (Iterator<Kitten> iter2 = kittens.iterator(); iter2.hasNext();) {
			Kitten w = iter2.next();
			ep = new Vector2(w.rect.x, w.rect.y);
			float dist = UsefulMethods.GetDistance(_sp, ep);
			if (dist < closestDistance && !w.isCarried && !w.isDead) {
				closestDistance = dist;
				_ep = ep;
			}
			_distances.put(closestDistance, _ep);
		}
		for (Float key : _distances.keySet()) {
			if (key < closestDistance)
				closestDistance = key;
		}
		Vector2 td = _distances.get(closestDistance);
		// System.out.println("distance?: " + td);
		if (!isEmpty(td))
			setTargetToClosestItem(td.x, td.y);
		else {
			Vector2 oopsNoOneIsLeft = new Vector2(harvester.rect.x, harvester.rect.y);
			td = oopsNoOneIsLeft;
		}
		return td;
	}

	private boolean isEmpty(Vector2 v) {
		if (v == null)
			return true;
		else
			return false;
	}

	private void setTargetToClosestItem(float _x, float _y) {
		targetX = _x;
		targetY = _y;
	}

	private void getCorrectWalkingAnimation(float dt) {
		if (Global.P.x > rect.x) {
			r = true;
		} else if (Global.P.x <= rect.x) {
			l = true;
		}
	}

	// for all the animations: //this isn't even updated unless i call it from the other screen oh bother. *facepalm*
	public TextureRegion getFrame(float dt, Array<Plant> plants, Array<Person> peoples, Array<Kitten> kittens, Harvester harvester) {
		Update(dt, plants, peoples, kittens, harvester);

		currentState = getState();
		// System.out.println("currentState: " + currentState);
		TextureRegion region;
		switch (currentState) {
		case WALKRIGHT:
			region = walkRight.getKeyFrame(_stateTimer, true);
			break;
		case WALKLEFT:
			region = walkLeft.getKeyFrame(_stateTimer, true);
			break;
		case HOLDLEFT:
			region = holdLeft.getKeyFrame(_stateTimer, true);
			break;
		case HOLDRIGHT:
			region = holdRight.getKeyFrame(_stateTimer, true);
			break;
		case DYING:
			region = dying.getKeyFrame(_stateTimer, true);
			break;
		default:
			region = walkRight.getKeyFrame(_stateTimer, true);
			break;
		}
		if (currentState != previousState)
			isAnimationOver = false;

		if (!isAnimationOver && currentState == previousState) {
			_stateTimer += dt;
		} else
			_stateTimer = 0;
		previousState = currentState;

		return region;
	}

	public void MoveFalling(float speed, float dt) {
		if (fallUpTimer > 0) {
			rect.y += speed * 2 * dt;
			fallUpTimer--;
			if (!Global.SetVolumeToZero)
				death.play();
		} else
			rect.y -= 2 * speed * dt;
	}

	public State getState() {
		// System.out.println("l: " + l + " r: " + r + " u: " + u + " d: " + d);
		// System.out.println("lmove: " + lmove + " rmove: " + rmove + " umove: " + umove + " dmove: " + dmove);
		if (isDying)
			return State.DYING;
		else if (isHolding && r)
			return State.HOLDRIGHT;
		else if (isHolding && l)
			return State.HOLDLEFT;
		else if (isHolding && u)
			return State.HOLDRIGHT;
		else if (isHolding && d)
			return State.HOLDLEFT;
		else if (r)
			return State.WALKRIGHT;
		else if (l)
			return State.WALKLEFT;
		else if (u)
			return State.WALKRIGHT;
		else if (d)
			return State.WALKLEFT;
		else
			return State.WALKRIGHT;
	}

	public void dispose() {
		death.dispose();
	}

	public void render(Agent game, float dt, Array<Plant> plants, Array<Person> peoples, Array<Kitten> kittens, Harvester harvester) {
		game.batch.draw(getFrame(dt, plants, peoples, kittens, harvester), rect.x, rect.y);
	}

}
