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.g2d.Animation;
import com.badlogic.gdx.graphics.g2d.Animation.PlayMode;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
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.utils.Array;
import com.ld50.game.HF;

import Global.Global;
import levelGen.Level;
import u.Uinput;

public class Player extends Sprite {
	public enum State {
		WALKRIGHT, WALKLEFT, WALKUP, WALKDOWN, STANDRIGHT, STANDLEFT, STANDUP, STANDDOWN, DYING
	};

	public State currentState;
	public State previousState;
	private Animation<TextureRegion> walkRight;
	private Animation<TextureRegion> walkLeft;
	private Animation<TextureRegion> walkUp;
	private Animation<TextureRegion> walkDown;
	private Animation<TextureRegion> dying;
	private TextureAtlas atlas;
	private TextureRegion standRight;
	private TextureRegion standLeft;
	private TextureRegion standUp;
	private TextureRegion standDown;
	private float _stateTimer;
	public Color color;
	public Float speed = 400f;
	public Rectangle rect;
	public Rectangle collRect;
	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
	// private Level _level;
	protected int MoveBufferX = 0, MoveBufferY = 0;
	private int fallUpTimer = 10;
	// sfx
	private Sound death;
	private Sound hurt;
	private Sound hurt2;
	private Sound hurt3;
	private Sound hurt4;
	private Sound hurt5;
	private Sound hurt6;
	private Sound shoot;
	private Sound shoot2;
	private Sound shoot3;
	private Sound click;
	private Sound click2;
	private Sound click3;
	private Sound click4;
	private Sound click5;
	private Sound click6;
	/// <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;
	public static boolean firesGun;
	public static boolean firesGun2;
	public static boolean outOfAmmo1 = true;
	public static boolean outOfAmmo2 = true;

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

		collRect = new Rectangle();
		collRect = rect;

		_sw = 100;
		_sh = 100;
		// _level = level;
		System.out.println("x: " + _x + "y: " + _y);

		speed = 20f;// how fast the goes
		// sounds
		death = Gdx.audio.newSound(Gdx.files.internal("sfx/death.ogg"));
		hurt = Gdx.audio.newSound(Gdx.files.internal("sfx/hurt.ogg"));
		hurt2 = Gdx.audio.newSound(Gdx.files.internal("sfx/hurt2.ogg"));
		hurt3 = Gdx.audio.newSound(Gdx.files.internal("sfx/hurt3.ogg"));
		hurt4 = Gdx.audio.newSound(Gdx.files.internal("sfx/hurt4.ogg"));
		hurt5 = Gdx.audio.newSound(Gdx.files.internal("sfx/hurt5.ogg"));
		hurt6 = Gdx.audio.newSound(Gdx.files.internal("sfx/hurt6.ogg"));
		shoot = Gdx.audio.newSound(Gdx.files.internal("sfx/shoot.ogg"));
		shoot2 = Gdx.audio.newSound(Gdx.files.internal("sfx/shoot2.ogg"));
		shoot3 = Gdx.audio.newSound(Gdx.files.internal("sfx/shoot3.ogg"));
		click = Gdx.audio.newSound(Gdx.files.internal("sfx/click.ogg"));
		click2 = Gdx.audio.newSound(Gdx.files.internal("sfx/click2.ogg"));
		click3 = Gdx.audio.newSound(Gdx.files.internal("sfx/click3.ogg"));
		click4 = Gdx.audio.newSound(Gdx.files.internal("sfx/click4.ogg"));
		click5 = Gdx.audio.newSound(Gdx.files.internal("sfx/click5.ogg"));
		click6 = Gdx.audio.newSound(Gdx.files.internal("sfx/click6.ogg"));
		// this is for the animations
		currentState = State.STANDRIGHT;
		previousState = State.STANDRIGHT;
		_stateTimer = 0f;
		// get Player atlas
		atlas = new TextureAtlas(Gdx.files.internal("player.txt"));
		// declare all the static frames (static states (no animation))
		standLeft = new TextureRegion(atlas.findRegion("player"), 0, 0, _sw, _sh);
		standLeft.flip(true, false);
		standRight = new TextureRegion(atlas.findRegion("player"), 0, 0, _sw, _sh);
		standUp = new TextureRegion(atlas.findRegion("player"), (3 * _sw), 0, _sw, _sh);
		standDown = new TextureRegion(atlas.findRegion("player"), (5 * _sw), 0, _sw, _sh);
		// animated frames
		Array<TextureRegion> frames = new Array<TextureRegion>();
		for (int i = 0; i <= 1; i++) {
			TextureRegion l = new TextureRegion(atlas.findRegion("player"), i * _sw, 0, _sw, _sh);
			l.flip(true, false);
			frames.add(l);
		}
		walkLeft = new Animation<TextureRegion>(.1f, frames, PlayMode.LOOP);
		frames.clear();
		for (int i = 0; i <= 1; i++) {
			frames.add(new TextureRegion(atlas.findRegion("player"), i * _sw, 0, _sw, _sh));
		}
		walkRight = new Animation<TextureRegion>(.1f, frames, PlayMode.LOOP);
		frames.clear();
		for (int i = 2; i <= 3; i++) {
			frames.add(new TextureRegion(atlas.findRegion("player"), i * _sw, 0, _sw, _sh));
		}
		walkUp = new Animation<TextureRegion>(.1f, frames, PlayMode.LOOP);
		frames.clear();
		for (int i = 4; i <= 5; i++) {
			frames.add(new TextureRegion(atlas.findRegion("player"), i * _sw, 0, _sw, _sh));
		}
		walkDown = new Animation<TextureRegion>(.1f, frames, PlayMode.LOOP);
		frames.clear();
		for (int i = 6; i <= 11; i++) {
			frames.add(new TextureRegion(atlas.findRegion("player"), i * _sw, 0, _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) {
		// setRegion(getFrame(dt));
		handleInput(dt, camera);
		checkIfDead();
		Global.P = rect;
		if (Gdx.input.isButtonJustPressed(Uinput.Fire())) {
			if (!outOfAmmo1 && !firesGun) {
				firesGun = true;
				playRandomShootSound(3);
			} else if (!outOfAmmo2 && !firesGun) {
				firesGun2 = true;
				playRandomShootSound(3);
			} else if (outOfAmmo1 && outOfAmmo2)
				playRandomClickSound(6);
		}
	}

	public void checkIfDead() {
		if (dead) {
			rmove = false;
			lmove = false;
			umove = false;
			dmove = false;
		}

	}

	public TextureRegion getFrame(float dt, OrthographicCamera camera) {
		// System.out.println("getting frame: " + getState());
		// System.out.println("_stateTimer: " + _stateTimer);
		// System.out.println("animation Index: " + walkLeft.getKeyFrame(_stateTimer));
		update(dt, camera);
		currentState = getState();
		// 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 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() {
		// 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 (r && rmove && dmove || r && rmove && umove)
			return State.WALKRIGHT;
		else if (l && lmove && umove || l && lmove && dmove)
			return State.WALKLEFT;
		else if (d && dmove && lmove || d && dmove && rmove)
			return State.WALKDOWN;
		else if (u && umove && lmove || u && umove && rmove)
			return State.WALKUP;
		else if (rmove)
			return State.WALKRIGHT;
		else if (lmove)
			return State.WALKLEFT;
		else if (umove)
			return State.WALKUP;
		else if (dmove)
			return State.WALKDOWN;
		else if (r)
			return State.STANDRIGHT;
		else if (l)
			return State.STANDLEFT;
		else if (u)
			return State.STANDUP;
		else if (d)
			return State.STANDDOWN;
		else
			return State.STANDRIGHT;
	}

	private void handleInput(float dt, OrthographicCamera camera) {
		boolean isCT = false;// collision tile

		if (Gdx.input.isKeyPressed(Uinput.Right())) {
			// isCT = false;
			isCT = (GetTileYouWillBeOn("right", dt)) ? true : false;// right
			MoveRight(speed, isCT, dt);
			l = false;
			r = true;
			u = false;
			d = false;
			rmove = true;
		} else
			rmove = false;
		if (Gdx.input.isKeyPressed(Uinput.Left())) {
			// isCT = false;
			isCT = (GetTileYouWillBeOn("left", dt)) ? true : false;// left
			MoveLeft(speed, isCT, dt);
			l = true;
			r = false;
			u = false;
			d = false;
			lmove = true;
		} else
			lmove = false;
		if (Gdx.input.isKeyPressed(Uinput.Up())) {
			// isCT = false;
			isCT = (GetTileYouWillBeOn("up", dt)) ? true : false;
			MoveUp(speed, isCT, dt);
			u = true;
			d = false;
			l = false;
			r = false;
			umove = true;
		} else
			umove = false;
		if (Gdx.input.isKeyPressed(Uinput.Down())) {
			// isCT = false;
			isCT = (GetTileYouWillBeOn("down", dt)) ? true : false;// down
			MoveDown(speed, isCT, dt);
			u = false;
			d = true;
			l = false;
			r = false;
			dmove = true;
		} else
			dmove = false;
		if (isDying)
			MoveFalling(speed, dt);
		// diag catches.
		if (Gdx.input.isKeyPressed(Uinput.Sprint()))
			speed = sprintSpeed;
		else
			speed = normSpeed;
		if (umove && lmove || umove && rmove || dmove && lmove || dmove && rmove) {
			if (speed == sprintSpeed)
				speed = sprintSpeed - sprintSpeed / 4;
			else
				speed = diagSpeed;
		} else if (sprintSpeed != speed)
			speed = normSpeed;
		// System.out.println("speeed: " + speed);
	}

	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 MoveRight(float speed, boolean isColl, float dt) {
		if (isColl)
			rect.x -= 0;
		else
			rect.x += speed * dt;
	}

	public void MoveLeft(float speed, boolean isColl, float dt) {
		// test this:
		if (isColl)
			rect.x += 0;
		else
			rect.x -= speed * dt;
	}

	public void MoveUp(float speed, boolean isColl, float dt) {
		// test this:
		if (isColl)
			rect.y -= 0;
		else
			rect.y += speed * dt;
	}

	public void MoveDown(float speed, boolean isColl, float dt) {
		// test this:
		if (isColl)
			rect.y += 0;
		else
			rect.y -= speed * dt;
	}

	public boolean GetTileYouWillBeOn(String dr, float dt) {
		// test to see what tile we will be standing on.
		if (dr == "right") {
			String _k = ("" + Math.abs(((int) rect.x + (int) (speed * dt)) / HF.TW) + "," + Math.abs((int) rect.y / HF.TH));
			String c = getMapId(_k);
			if (c == "null")
				return true;// collision tile
			else
				return false;
		}
		if (dr == "left") {
			String _k = ("" + Math.abs(((int) rect.x - (int) (speed * dt)) / HF.TW) + "," + Math.abs((int) rect.y / HF.TH));
			String c = getMapId(_k);
			if (c == "null")
				return true;// collision tile
			else
				return false;
		}
		if (dr == "up") {
			String _k = ("" + Math.abs((int) rect.x / HF.TW) + "," + Math.abs((int) (rect.y + (int) (speed * dt)) / HF.TH));
			String c = getMapId(_k);
			if (c == "null")
				return true;// collision tile
			else
				return false;
		}
		if (dr == "down") {
			String _k = ("" + Math.abs((int) rect.x / HF.TW) + "," + Math.abs((int) (rect.y - (int) (speed * dt)) / HF.TH));
			String c = getMapId(_k);
			if (c == "null")
				return true;// collision tile
			else
				return false;
		} else
			return false;
	}

	public String getMapId(String _k) {
		Integer _o = Level.Map.get(_k);
		String s;
		if (_o == null)// translate the integers into actual, um, tile types
			s = "null";
		else if (_o == 0)
			s = "water";
		else if (_o == 1)
			s = "rock";
		else if (_o == 2)
			s = "grass";
		else if (_o == 3)
			s = "deep water";
		else if (_o == 4)
			s = "deepest water";
		else if (_o == 5)
			s = "dark rock";
		else if (_o == 6)
			s = "snow";
		else if (_o == 7)
			s = "sand";
		else if (_o == 8)
			s = "lava";
		else
			s = "something else";
		// System.out.println("tileType: " + s);
		return s;
	}

	public void playRandomHurtSound(int numberOfSounds) {
		int randomSound = MathUtils.random(1, numberOfSounds);
		if (!Global.SetVolumeToZero) {
			if (randomSound == 1)
				hurt.play();
			else if (randomSound == 2)
				hurt2.play();
			else if (randomSound == 3)
				hurt3.play();
			else if (randomSound == 4)
				hurt4.play();
			else if (randomSound == 5)
				hurt5.play();
			else if (randomSound == 6)
				hurt6.play();
		}
	}

	public void playRandomShootSound(int numberOfSounds) {
		int randomSound = MathUtils.random(1, numberOfSounds);
		if (!Global.SetVolumeToZero) {
			if (randomSound == 1)
				shoot.play();
			else if (randomSound == 2)
				shoot2.play();
			else if (randomSound == 3)
				shoot3.play(.8f);
		}
	}

	public void playRandomClickSound(int numberOfSounds) {
		int randomSound = MathUtils.random(1, numberOfSounds);
		if (!Global.SetVolumeToZero) {
			if (randomSound == 1)
				click.play(.2f);
			else if (randomSound == 2)
				click2.play(.2f);
			else if (randomSound == 3)
				click3.play(.2f);
			else if (randomSound == 4)
				click4.play(.2f);
			else if (randomSound == 5)
				click5.play(.2f);
			else if (randomSound == 6)
				click6.play(.2f);
		}
	}

	public void dispose() {
		atlas.dispose();
		death.dispose();
		hurt.dispose();
		hurt2.dispose();
		hurt3.dispose();
		hurt4.dispose();
		hurt5.dispose();
		hurt6.dispose();
		shoot.dispose();
		shoot2.dispose();
		shoot3.dispose();
		click.dispose();
		click2.dispose();
		click3.dispose();
		click4.dispose();
		click5.dispose();
		click6.dispose();
	}
}
