package entities;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.audio.Sound;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.OrthographicCamera;
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.graphics.glutils.ShapeRenderer;
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 Global.Global;
import u.UsefulMethods;

public class EvilAgent extends Sprite {
	public enum State {
		STANDLEFT, STANDRIGHT, STANDUP, STANDDOWN, WALKLEFT, WALKRIGHT, WALKUP, WALKDOWN, SHOOTSTANDLEFT, SHOOTSTANDRIGHT, SHOOTSTANDUP, SHOOTSTANDDOWN,
		SHOOTWALKLEFT, SHOOTWALKRIGHT, SHOOTWALKUP, SHOOTWALKDOWN, DYING
	};

	public State currentState;
	public State previousState;
	private Animation<TextureRegion> walkLeft;
	private Animation<TextureRegion> walkRight;
	private Animation<TextureRegion> walkUp;
	private Animation<TextureRegion> walkDown;
	private Animation<TextureRegion> shootWalkLeft;
	private Animation<TextureRegion> shootWalkRight;
	private Animation<TextureRegion> shootWalkUp;
	private Animation<TextureRegion> shootWalkDown;
	private Animation<TextureRegion> dying;
	// private TextureAtlas atlas;
	private Texture t1;
	private TextureRegion standLeft;
	private TextureRegion standRight;
	private TextureRegion standUp;
	private TextureRegion standDown;
	private TextureRegion shootStandLeft;
	private TextureRegion shootStandRight;
	private TextureRegion shootStandUp;
	private TextureRegion shootStandDown;
	private float _stateTimer;
	public Color color;
	public Float speed = 300f;// was 400
	public Rectangle rect;
	public ShapeRenderer sr;
	private boolean isAnimationOver;
	public boolean dead;
	public boolean rmove;
	public boolean lmove;
	public boolean umove;
	public boolean dmove;
	public boolean isDying;
	public static boolean r;
	public static boolean l;
	public static boolean u;
	public static boolean d;
	private int _sw;// sprite width
	private int _sh;// sprite height
	protected int MoveBufferX = 0, MoveBufferY = 0;
	private int fallUpTimer = 10;
	// sfx
	private Sound death;
	private Sound hurt;
	private Sound click;
	/// <summary> //i have no idea if this translates. This is from another collider program because i can't invent this stuff a bizzilions times
	/// Determines how many units represent 1 pixel. Default is 100. Example: A speed of 100 would
	/// move the object 1 pixel per update.
	/// </summary>
	public int SpeedScale = 100;// this... um. did nothing hehehehahahhaha
	private float normSpeed = speed;
	private float diagSpeed = speed - speed / 4;
	private float sprintSpeed = speed * 2;
	private float jumpMax = 10;
	private float jumpingTimer = jumpMax;
	public boolean isJumping = false;
	public static boolean firesGun;
	public static boolean outOfAmmo = true;
	// testing vectors
	Vector2 position = new Vector2();
	Vector2 velocity = new Vector2();
	Vector2 movement = new Vector2();
	Vector2 touch = new Vector2();
	Vector2 dir = new Vector2();
	Vector2 dirUp = new Vector2(0, 1);
	Vector2 dirDown = new Vector2(0, -1);
	Vector2 dirLeft = new Vector2(-1, 0);
	Vector2 dirRight = new Vector2(1, 0);
	Vector2 dirRightUp = new Vector2(1, 1);
	Vector2 dirRightDown = new Vector2(1, -1);
	Vector2 dirLeftUp = new Vector2(-1, 1);
	Vector2 dirLeftDown = new Vector2(1, -1);
	public boolean hasGun;
	public boolean isReloading;
	private Float duckSpeed = speed / 2;
	public int ammoSize = 8;
	public int ammo = ammoSize;

	public EnemyBall enemyBall;
	public Drum drum;
	public Beam beam;
	private boolean isFireEnemyBall;
	private boolean initOne;
	private float targetX;
	private float targetY;
	private int fireTimer;
	private int FireTimerMax = MathUtils.random(50, 1500);
	private int fireDrumTimer;
	private int FireDrumTimerMax = MathUtils.random(6000, 40000);
	private int fireBeamTimer;
	private int FireBeamTimerMax = MathUtils.random(6000, 50000);
	private boolean isFireDrum;
	private boolean initOneDrum;
	private boolean isFireBeam;
	private boolean initOneBeam;
	public boolean isSpinning;

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

		fireTimer = FireTimerMax;

		_sw = 32;
		_sh = 32;
		// _level = level;
		enemyBall = new EnemyBall(_x, _y, _x, _y);
		drum = new Drum(_x, _y, _x, _y);
		beam = new Beam(_x, _y, _x, _y);

		// set location and intial velocities?
		position.set(rect.getX(), rect.getY());
		// sounds
		death = Gdx.audio.newSound(Gdx.files.internal("sfx/death.ogg"));
		hurt = Gdx.audio.newSound(Gdx.files.internal("sfx/hurt.ogg"));
		click = Gdx.audio.newSound(Gdx.files.internal("sfx/click.ogg"));
		// this is for the animations
		currentState = State.STANDRIGHT;
		previousState = State.STANDRIGHT;
		_stateTimer = 0f;
		// get Player atlas
		// atlas = new TextureAtlas(Gdx.files.internal("playersheettest.png"));
		t1 = new Texture(Gdx.files.internal("evilAgent.png"));
		// declare all the static frames (static states (no animation))
		standLeft = new TextureRegion(t1, (0 * _sw), (0 * _sh), _sw, _sh);
		standRight = new TextureRegion(t1, (1 * _sw), (0 * _sh), _sw, _sh);
		standUp = new TextureRegion(t1, (2 * _sw), (0 * _sh), _sw, _sh);
		standDown = new TextureRegion(t1, (3 * _sw), (0 * _sh), _sw, _sh);
		shootStandLeft = new TextureRegion(t1, (8 * _sw), (0 * _sh), _sw, _sh);
		shootStandRight = new TextureRegion(t1, (9 * _sw), (0 * _sh), _sw, _sh);
		shootStandUp = new TextureRegion(t1, (10 * _sw), (0 * _sh), _sw, _sh);
		shootStandDown = new TextureRegion(t1, (11 * _sw), (0 * _sh), _sw, _sh);
		// animated frames
		Array<TextureRegion> frames = new Array<TextureRegion>();
		frames.add(new TextureRegion(t1, (0 * _sw), (0 * _sh), _sw, _sh));
		frames.add(new TextureRegion(t1, (4 * _sw), (0 * _sh), _sw, _sh));
		walkLeft = new Animation<TextureRegion>(.1f, frames, PlayMode.LOOP);
		frames.clear();
		frames.add(new TextureRegion(t1, (1 * _sw), (0 * _sh), _sw, _sh));
		frames.add(new TextureRegion(t1, (5 * _sw), (0 * _sh), _sw, _sh));
		walkRight = new Animation<TextureRegion>(.1f, frames, PlayMode.LOOP);
		frames.clear();
		frames.add(new TextureRegion(t1, (2 * _sw), (0 * _sh), _sw, _sh));
		frames.add(new TextureRegion(t1, (6 * _sw), (0 * _sh), _sw, _sh));
		walkUp = new Animation<TextureRegion>(.1f, frames, PlayMode.LOOP);
		frames.clear();
		frames.add(new TextureRegion(t1, (3 * _sw), (0 * _sh), _sw, _sh));
		frames.add(new TextureRegion(t1, (7 * _sw), (0 * _sh), _sw, _sh));
		walkDown = new Animation<TextureRegion>(.1f, frames, PlayMode.LOOP);
		frames.clear();
		frames.add(new TextureRegion(t1, (8 * _sw), (0 * _sh), _sw, _sh));
		frames.add(new TextureRegion(t1, (12 * _sw), (0 * _sh), _sw, _sh));
		shootWalkLeft = new Animation<TextureRegion>(.1f, frames, PlayMode.LOOP);
		frames.clear();
		frames.add(new TextureRegion(t1, (9 * _sw), (0 * _sh), _sw, _sh));
		frames.add(new TextureRegion(t1, (13 * _sw), (0 * _sh), _sw, _sh));
		shootWalkRight = new Animation<TextureRegion>(.1f, frames, PlayMode.LOOP);
		frames.clear();
		frames.add(new TextureRegion(t1, (10 * _sw), (0 * _sh), _sw, _sh));
		frames.add(new TextureRegion(t1, (14 * _sw), (0 * _sh), _sw, _sh));
		shootWalkUp = new Animation<TextureRegion>(.1f, frames, PlayMode.LOOP);
		frames.clear();
		frames.add(new TextureRegion(t1, (11 * _sw), (0 * _sh), _sw, _sh));
		frames.add(new TextureRegion(t1, (15 * _sw), (0 * _sh), _sw, _sh));
		shootWalkDown = new Animation<TextureRegion>(.1f, 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));
		frames.add(new TextureRegion(t1, (8 * _sw), (0 * _sh), _sw, _sh));
		frames.add(new TextureRegion(t1, (9 * _sw), (0 * _sh), _sw, _sh));
		frames.add(new TextureRegion(t1, (10 * _sw), (0 * _sh), _sw, _sh));
		frames.add(new TextureRegion(t1, (11 * _sw), (0 * _sh), _sw, _sh));
		frames.add(new TextureRegion(t1, (12 * _sw), (0 * _sh), _sw, _sh));
		frames.add(new TextureRegion(t1, (13 * _sw), (0 * _sh), _sw, _sh));
		frames.add(new TextureRegion(t1, (14 * _sw), (0 * _sh), _sw, _sh));
		frames.add(new TextureRegion(t1, (15 * _sw), (0 * _sh), _sw, _sh));
		dying = new Animation<TextureRegion>(.2f, frames, PlayMode.LOOP);
		frames.clear();// definitely starts right. then we say, when the line is one length + one _sw worth which would be what in actual numbers?
		// these two are specifically sprite settings to set the sprite's initial bounds and region
		// assign random color
		color = new Color(Color.WHITE);// new Color(MathUtils.random(), MathUtils.random(), MathUtils.random(), 1);
		setBounds(0, 0, _sw, _sh);
		setRegion(standRight);
		r = true;
	}

	// for all the animations: //this isn't even updated unless i call it from the other screen oh bother. *facepalm*
	public void update(float dt, OrthographicCamera camera, Player player) {
		hasGun = true;
		if (fireTimer > 0)
			fireTimer--;
		if (fireTimer <= 0) {
			isFireEnemyBall = false;
			initOne = false;
		}
		if (!isFireEnemyBall) {
			isFireEnemyBall = true;
			if (!initOne) {
				initOne = true;
				enemyBall.rect.x = rect.x;
				enemyBall.rect.y = rect.y;
				enemyBall.shadow.rect.x = rect.x;
				enemyBall.shadow.rect.y = rect.y - 20;
			}
			enemyBall.sp = new Vector2(rect.x, rect.y);
			enemyBall.ep = new Vector2(player.rect.x, player.rect.y);
			enemyBall.dir = UsefulMethods.GetDirection(enemyBall.sp, enemyBall.ep);
			enemyBall.isDead = false;
			enemyBall.fired = true;
			// same for the shadow
			Vector2 sps = new Vector2(rect.x, rect.y);
			sps.y -= 20;
			Vector2 eps = new Vector2(player.rect.x, player.rect.y);
			eps.y -= 20;
			enemyBall.shadow.sp = sps;
			enemyBall.shadow.ep = eps;
			enemyBall.shadow.dir = UsefulMethods.GetDirection(enemyBall.sp, enemyBall.ep);
			enemyBall.shadow.isDead = false;
			enemyBall.shadow.fired = true;
			fireTimer = FireTimerMax;
		}
		if (fireDrumTimer > 0) {
			fireDrumTimer--;
			// System.out.println("drumtimer" + fireDrumTimer);
		}
		if (fireDrumTimer <= 0) {
			isFireDrum = false;
			initOneDrum = false;
		}
		if (!isFireDrum) {
			isFireDrum = true;
			if (!initOneDrum) {
				initOneDrum = true;
				drum.rect.x = rect.x;
				drum.rect.y = rect.y;
				// enemyBall.shadow.rect.x = rect.x;
				// enemyBall.shadow.rect.y = rect.y - 20;
			}
			drum.sp = new Vector2(rect.x, rect.y);
			drum.ep = new Vector2(player.rect.x, player.rect.y);
			drum.dir = UsefulMethods.GetDirection(drum.sp, drum.ep);
			drum.isDead = false;
			drum.fired = true;
			// System.out.println("fireDrumTimerMax" + FireDrumTimerMax);
			fireDrumTimer = FireDrumTimerMax;
		}
		if (fireBeamTimer > 0) {
			fireBeamTimer--;
			// System.out.println("beamtimer" + fireBeamTimer);
		}
		if (fireBeamTimer <= 0) {
			isFireBeam = false;
			initOneBeam = false;
		}
		if (!isFireBeam) {
			isFireBeam = true;
			if (!initOneBeam) {
				initOneBeam = true;
				beam.rect.x = rect.x;
				beam.rect.y = rect.y;
				beam.shadow.rect.x = rect.x;
				beam.shadow.rect.y = rect.y - 20;
			}
			beam.sp = new Vector2(rect.x, rect.y);
			beam.ep = new Vector2(player.rect.x, player.rect.y);
			beam.dir = UsefulMethods.GetDirection(beam.sp, beam.ep);
			beam.isDead = false;
			beam.fired = true;
			// same for the shadow
			Vector2 sps = new Vector2(rect.x, rect.y);
			sps.y -= 20;
			Vector2 eps = new Vector2(player.rect.x, player.rect.y);
			eps.y -= 20;
			beam.shadow.sp = sps;
			beam.shadow.ep = eps;
			beam.shadow.dir = UsefulMethods.GetDirection(beam.sp, beam.ep);
			beam.shadow.isDead = false;
			beam.shadow.fired = true;

			// System.out.println("fireBeamTimerMax" + FireBeamTimerMax);
			fireBeamTimer = FireBeamTimerMax;
		}
		// System.out.println("isFireEnemyBall: " + isFireEnemyBall);
		// System.out.println("speed: " + enemyBall.speed);
	}

	public TextureRegion getFrame(OrthographicCamera camera, float dt, Player player) {
		// System.out.println("getting frame: " + getState());
		// System.out.println("_stateTimer: " + _stateTimer);
		// System.out.println("animation Index: " + walkLeft.getKeyFrame(_stateTimer));
		update(dt, camera, player);
		currentState = getState(player);
		// System.out.println("state: " + currentState);
		TextureRegion region;
		switch (currentState) {
		case WALKRIGHT:
			region = walkRight.getKeyFrame(_stateTimer, true);
			break;
		case WALKLEFT:
			region = walkLeft.getKeyFrame(_stateTimer, true);
			break;
		case WALKUP:
			region = walkUp.getKeyFrame(_stateTimer, true);
			break;
		case WALKDOWN:
			region = walkDown.getKeyFrame(_stateTimer, true);
			break;
		case STANDLEFT:
			region = standLeft;
			break;
		case STANDUP:
			region = standUp;
			break;
		case STANDDOWN:
			region = standDown;
			break;
		case SHOOTWALKRIGHT:
			region = shootWalkRight.getKeyFrame(_stateTimer, true);
			break;
		case SHOOTWALKLEFT:
			region = shootWalkLeft.getKeyFrame(_stateTimer, true);
			break;
		case SHOOTWALKUP:
			region = shootWalkUp.getKeyFrame(_stateTimer, true);
			break;
		case SHOOTWALKDOWN:
			region = shootWalkDown.getKeyFrame(_stateTimer, true);
			break;
		case SHOOTSTANDLEFT:
			region = shootStandLeft;
			break;
		case SHOOTSTANDRIGHT:
			region = shootStandRight;
			break;
		case SHOOTSTANDUP:
			region = shootStandUp;
			break;
		case SHOOTSTANDDOWN:
			region = shootStandDown;
			break;
		case DYING:
			region = dying.getKeyFrame(_stateTimer, true);
			break;
		case STANDRIGHT:
		default:
			region = standRight;
			break;
		}
		if (currentState != previousState)
			isAnimationOver = false;

		if (!isAnimationOver && currentState == previousState) {
			_stateTimer += dt;
		} else
			_stateTimer = 0;
		// System.out.println("statetimer: " + _stateTimer);
		previousState = currentState;

		return region;
	}

	public State getState(Player player) {
		// System.out.println("l: " + l + " r: " + r + " u: " + u + " d: " + d);
		// System.out.println("lmove: " + lmove + " rmove: " + rmove + " umove: " + umove + " dmove: " + dmove);
		hasGun = true;
		if (isDying)
			return State.DYING;
		if (isSpinning)
			return State.DYING;
		if (player.rect.x >= rect.x)
			return State.SHOOTSTANDRIGHT;
		if (player.rect.y >= rect.y)
			return State.SHOOTSTANDUP;
		if (player.rect.x < rect.x)
			return State.SHOOTSTANDLEFT;
		if (player.rect.y < rect.y)
			return State.SHOOTSTANDDOWN;
//		else if (hasGun && l && lmove && umove || hasGun && l && lmove && dmove)
//			return State.SHOOTWALKLEFT;
//		else if (hasGun && r && rmove && dmove || hasGun && r && rmove && umove)
//			return State.SHOOTWALKRIGHT;
//		else if (hasGun && u && umove && lmove || hasGun && u && umove && rmove)
//			return State.SHOOTWALKUP;
//		else if (hasGun && d && dmove && lmove || hasGun && d && dmove && rmove)
//			return State.SHOOTWALKDOWN;
//		else if (hasGun && lmove)
//			return State.SHOOTWALKLEFT;
//		else if (hasGun && rmove)
//			return State.SHOOTWALKRIGHT;
//		else if (hasGun && umove)
//			return State.SHOOTWALKUP;
//		else if (hasGun && dmove)
//			return State.SHOOTWALKDOWN;
//		else if (hasGun && l)
//			return State.SHOOTSTANDLEFT;
//		else if (hasGun && r)
//			return State.SHOOTSTANDRIGHT;
//		else if (hasGun && u)
//			return State.SHOOTSTANDUP;
//		else if (hasGun && d)
//			return State.SHOOTSTANDDOWN;
//		else if (l && lmove && umove || l && lmove && dmove)
//			return State.WALKLEFT;
//		else if (r && rmove && dmove || r && rmove && umove)
//			return State.WALKRIGHT;
//		else if (u && umove && lmove || u && umove && rmove)
//			return State.WALKUP;
//		else if (d && dmove && lmove || d && dmove && rmove)
//			return State.WALKDOWN;
//		else if (lmove)
//			return State.WALKLEFT;
//		else if (rmove)
//			return State.WALKRIGHT;
//		else if (umove)
//			return State.WALKUP;
//		else if (dmove)
//			return State.WALKDOWN;
//		else if (l)
//			return State.STANDLEFT;
//		else if (r)
//			return State.STANDRIGHT;
//		else if (u)
//			return State.STANDUP;
//		else if (d)
//			return State.STANDDOWN;
		else
			return State.STANDRIGHT;
	}

	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 void playRandomHurtSound() {
		if (!Global.SetVolumeToZero) {
			hurt.play();
		}
	}

	public void playRandomClickSound() {
		if (!Global.SetVolumeToZero) {
			click.play(.2f);
		}
	}

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

	public void render(Agent game, OrthographicCamera camera, float dt, Player player) {
		game.batch.draw(getFrame(camera, dt, player), rect.x, rect.y);
	}
}
