using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class CopMovement : MonoBehaviour {

	public CopPoint goalPoint;
	public Vector3 goal;
	public float speed, visionRange, visionAngle, idleTurnSpeed, appearCooldown, disappearCooldown, alertCooldown,
        chaseSpeed, chaseAcc, chaseTurnSpeed, chaseStartSpeed;
	public Status status;

	private Rigidbody2D rigidThing;
	private float visionCooldown, stopCooldown;
	private Light flashlight;
    private float currentSpeed;


	public enum Status
	{
		Walking,
		Turning,
		Chasing,
		Alert
	}

	void Start ()
	{
        currentSpeed = chaseStartSpeed;
		//CollisionHelper.ignoreCollisionWithTag (gameObject, "Player", true);
		CollisionHelper.ignoreCollisionWithTag (gameObject, "Cop", true);
		rigidThing = GetComponent<Rigidbody2D> ();
        reset();
		flashlight = transform.FindChild ("Flashlight").GetComponent<Light> ();
		updateFlashlight ();
		visionCooldown = appearCooldown;
		QualitySettings.pixelLightCount++;
	}

	void Update ()
    {
        visionRange = 15 * Mathf.Pow(getSpeedMult(), .15f);
        updateFlashlight();

        float diff = speed * Time.deltaTime * Mathf.Pow(getSpeedMult(), .6f);

		switch(status)
		{
		case(Status.Walking):
			if (MathHelper.get2DDifference(transform.position, goal).magnitude <= diff)
			{
				transform.position = new Vector3(goal.x, goal.y, transform.position.z);
				
				findNewPoint();
				status = Status.Turning;
				rigidThing.velocity = Vector2.zero;
			}
			else
				rigidThing.velocity = MathHelper.resizeVector ((Vector2)goal - (Vector2)transform.position, diff / Time.deltaTime);
			checkForPlayerAppear();
			break;
		case(Status.Turning):
			if (!seesPlayer())
				updateTurning();
			checkForPlayerAppear();
				break;
		case(Status.Chasing):
			updateChaseMovement();
			checkForPlayerDisappear();
			break;
		case(Status.Alert):
			checkForPlayerAppear();
			alertCooldown -= Time.deltaTime;
			if (alertCooldown <= 0f)
			{
				Debug.Log("AND NOW I MUST RETURN TO MY ROUTE AS A FAITHFUL COP");
				status = Status.Turning;
				visionCooldown = appearCooldown;
			}
			break;
		default:
			break;
		}

        if (UpgradeController.instance.gameObject.activeInHierarchy)
        {
            rigidThing.velocity = Vector2.zero;
        }
	
	}

    public void reset()
    {
        goalPoint = null;
        visionCooldown = 0f;
        findNewPoint();
        transform.position = new Vector3(goal.x, goal.y, transform.position.z);
        setAngle(Random.Range(0f, Mathf.PI * 2f));
    }

	void updateChaseMovement()
	{
		float goalAngle = MathHelper.getVectorAngle ((Vector2)PlayerMovement.instance.transform.position - (Vector2)transform.position),
			angleDiff = MathHelper.getAngleDifference (goalAngle, getAngle()), diff = chaseTurnSpeed * Time.deltaTime *
            Mathf.Pow(getSpeedMult(), .6f);
		
		if (Mathf.Abs (angleDiff) <= diff)
		{
			setAngle (goalAngle);
		}
		else if (angleDiff < 0f)
		{
			setAngle (getAngle () + diff);
		}
		else
		{
			setAngle (getAngle () - diff);
		}

        //currentspeed += chaseAcc * Time.deltaTime;


        currentSpeed += chaseAcc * Time.deltaTime * getSpeedMult();
        if (currentSpeed > chaseSpeed * getSpeedMult())
            currentSpeed = chaseSpeed * getSpeedMult();

        rigidThing.velocity = MathHelper.getVectorFromAngle(getAngle(), currentSpeed);


    }


    public float getSpeedMult()
    {
        return (chaseSpeed + ((float)(GameController.instance.day - 1) * UpgradeController.instance.copSpeedIncrease)) / chaseSpeed;
    }

	void checkForPlayerAppear()
	{
		if (seesPlayer())
		{
			rigidThing.velocity = Vector2.zero;
			visionCooldown -= Time.deltaTime * (Mathf.Lerp(10f, 1f, ((Vector2)(transform.position - PlayerMovement.instance.transform.position)).magnitude / visionRange)
                * Mathf.Pow(getSpeedMult(), .5f));
			if (visionCooldown < 0f || status == Status.Alert)
			{
				visionCooldown = disappearCooldown;
				status = Status.Chasing;
			}
		}
		else 
			visionCooldown = appearCooldown;
	}

	void checkForPlayerDisappear()
	{
		if (!seesPlayer())
		{
			//Debug.Log("OH WHERE DID HE GO");
			//rigidThing.velocity = Vector2.zero;
			visionCooldown -= Time.deltaTime;
			if (visionCooldown < 0f)
			{
                currentSpeed = chaseStartSpeed;
				//Debug.Log("MUST'VE BEEN THE WIND");
				findNewPoint();
				status = Status.Alert;
				alertCooldown = alertCooldown;
				visionCooldown = appearCooldown;
				rigidThing.velocity = Vector2.zero;
				visionCooldown = appearCooldown;
			}
		}
		else 
			visionCooldown = disappearCooldown;
	}

	void updateTurning()
	{
		float goalAngle = MathHelper.getVectorAngle ((Vector2)goal - (Vector2)transform.position),
		angleDiff = MathHelper.getAngleDifference (goalAngle, getAngle()), diff = idleTurnSpeed * Time.deltaTime;

		if (Mathf.Abs (angleDiff) <= diff)
		{
			setAngle (goalAngle);
			if (status == Status.Turning)
				status = Status.Walking;
		}
		else if (angleDiff < 0f)
		{
			setAngle (getAngle () + diff);
		}
		else
		{
			setAngle (getAngle () - diff);
		}
	}

	void findNewPoint()
	{
		List<CopPoint> availablePoints = new List<CopPoint>();
		GameObject[] copPoints = GameController.instance.getCopPoints();
        if (goalPoint != null)
        {
            for (int i = 0; i < copPoints.Length; i++)
            {
                Transform newPoint = copPoints[i].transform;
                if (
                    //(goalPoint == null && ((Vector2)(newPoint.transform.position - PlayerMovement.instance.transform.position)).magnitude >
                    //PlayerMovement.instance.copLightRange) ||
                    (!Physics2D.Raycast((Vector2)transform.position, MathHelper.resizeVector((Vector2)newPoint.transform.position - (Vector2)transform.position, 1f),
                    ((Vector2)newPoint.transform.position - (Vector2)transform.position).magnitude, Physics2D.DefaultRaycastLayers)
                    && newPoint.GetComponent<CopPoint>() != goalPoint))
                {
                    availablePoints.Add(newPoint.GetComponent<CopPoint>());
                }
            }
            if (availablePoints.Count > 0f)
                goalPoint = availablePoints[Random.Range(0, availablePoints.Count)];
        }
        else
        {
            do
            {
                goalPoint = copPoints[Random.Range(0, copPoints.Length)].GetComponent<CopPoint>(); ;
            }
            while (((Vector2)(goalPoint.transform.position - PlayerMovement.instance.transform.position)).magnitude <
                    PlayerMovement.instance.copLightRange);
        }
        goal = goalPoint.transform.position + (Vector3)MathHelper.getVectorFromAngle(Random.Range(0f, Mathf.PI * 2f),
			Random.Range(0f, goalPoint.GetComponent<CircleCollider2D>().radius));
	}

    

	bool seesPlayer()
	{
        /*
		Debug.Log (getAngle ());
		Debug.Log (MathHelper.getVectorAngle ((Vector2)PlayerMovement.instance.transform.position - (Vector2)transform.position));
		Debug.Log (MathHelper.getAngleDifference (MathHelper.getVectorAngle ((Vector2)PlayerMovement.instance.transform.position - (Vector2)transform.position),
		                                        getAngle ()));

		
		Vector2 diff = (Vector2)PlayerMovement.instance.transform.position - (Vector2)transform.position;
		*/

        //Debug.Log(flashlight);
		Debug.DrawLine(flashlight.transform.position, flashlight.transform.position + (Vector3)MathHelper.getVectorFromAngle(getAngle() - visionAngle, visionRange));
		Debug.DrawLine(flashlight.transform.position, flashlight.transform.position + (Vector3)MathHelper.getVectorFromAngle(getAngle() + visionAngle, visionRange));

		
		/*Debug.Log(MathHelper.getAngleDifference(MathHelper.getVectorAngle((Vector2)PlayerMovement.instance.transform.position - (Vector2)flashlight.transform.position),
		                                        getAngle()));
		Debug.Log(((Vector2)PlayerMovement.instance.transform.position - (Vector2)flashlight.transform.position).magnitude);

*/
		return (Mathf.Abs (MathHelper.getAngleDifference(MathHelper.getVectorAngle((Vector2)PlayerMovement.instance.transform.position - (Vector2)flashlight.transform.position),
		        getAngle())) < visionAngle)

			&& ((Vector2)PlayerMovement.instance.transform.position - (Vector2)flashlight.transform.position).magnitude <= visionRange

			&& !Physics2D.Raycast((Vector2)flashlight.transform.position,
			                      MathHelper.resizeVector((Vector2)PlayerMovement.instance.transform.position - (Vector2)flashlight.transform.position, 1f),
			                      ((Vector2)PlayerMovement.instance.transform.position - (Vector2)flashlight.transform.position).magnitude,
				                      Physics2D.DefaultRaycastLayers, -10f);


	}

	void updateFlashlight()
	{
        if (flashlight == null)
            flashlight = transform.FindChild("Flashlight").GetComponent<Light>();
        flashlight.spotAngle = visionAngle * 2f * 180f / Mathf.PI;
		flashlight.range = visionRange * 1.75f; 

		flashlight.enabled = ((Vector2)transform.position - (Vector2)PlayerMovement.instance.transform.position).magnitude <= PlayerMovement.instance.copLightRange;
	}

	
	void setAngle(float angle)
	{
		transform.rotation = Quaternion.EulerAngles (0f, 0f, angle - (Mathf.PI / 2f));
	}
		    
	float getAngle()
	{
		return ((transform.eulerAngles.z* Mathf.PI / 180f) + (Mathf.PI / 2f));
	}
}