using UnityEngine;
using System.Collections;

public class MaitreD : MonoBehaviour 
{
    public Rigidbody myRigidbody;
    public AIMode aiMode = AIMode.Idle;
    public float turnSpeed = 3.5f;
    public float walkSpeed = 10f;
    public float maxSpeed = 3.5f;
    public float dignity = 3f;
    public float jumpForce = 10f;
    public string[] retorts;
    public bool wasKilled;

    public float walkRaw;
    public float turnRaw;

    public float heading;
    private bool canJump;
    private PlayerController playerController;
    private int lastPursuitScore;
    private AudioSource footstepAudio;

    private bool CanJump()
    {
        //return Physics.Raycast(new Ray(transform.position + new Vector3(0f, 0.01f, 0f), Vector3.down), 0.021f, Layers.GetMask(Layers.Floor) | Layers.GetMask(Layers.Furnishing));
        return Physics.SphereCast(new Ray(transform.position + new Vector3(0f, 0.36f, 0f), Vector3.down), 0.35f, 0.021f, Layers.GetMask(Layers.Floor) | Layers.GetMask(Layers.Furnishing));
    }


    private void IdleUpdate()
    {
        walkRaw = 0f;
        turnRaw = 0f;
        if(playerController.score > lastPursuitScore)
        {
            aiMode = AIMode.Pursuing;
            footstepAudio.Play();
        }
    }

	private void FleeingUpdate()
    {
        var targetPosition = new Vector3(17f, 0f, 9.5f);
        var desiredHeading = VectorXZToAngle(targetPosition - transform.position);

        if ((targetPosition - transform.position).sqrMagnitude < 1f)
        {
            aiMode = AIMode.Idle;
            gameObject.SetLayerRecursively(Layers.Target);
            wasKilled = false;
            dignity = 1;
        }
        //Debug.Log(desiredHeading);

        walkRaw = 1f;
        turnRaw = Mathf.Sign(desiredHeading - heading);

    }

    private void PursuingUpdate()
    {
        var targetPosition = playerController.transform.position;
        var desiredHeading = VectorXZToAngle(targetPosition - transform.position);
        //Debug.Log(desiredHeading);

        walkRaw = 1f;
        turnRaw = Mathf.Sign(desiredHeading - heading);

    }

    private void MovementUpdate()
    {
        if (Mathf.Abs(turnRaw) > 0.0f)
        {
            heading += turnSpeed * turnRaw;
        }

        heading = ClampAngle(heading, -360f, 360f);
        Quaternion xQuaternion = Quaternion.AngleAxis(heading, Vector3.up);
        transform.localRotation = xQuaternion;
    }

    private void Jump()
    {
        myRigidbody.AddForce(new Vector3(0f, jumpForce, 0f), ForceMode.VelocityChange);
    }

    void Awake()
    {
        footstepAudio = GetComponent<AudioSource>();
        playerController = FindObjectOfType<PlayerController>();
    }

    void Start()
    {
        heading = transform.rotation.eulerAngles.y;
    }

	void Update () 
    {
        switch(aiMode)
        {
            case AIMode.Idle:
                IdleUpdate();
                break;
            case AIMode.Pursuing:
                PursuingUpdate();
                break;
            case AIMode.Fleeing:
                FleeingUpdate();
                break;
        }
        MovementUpdate();
	
	}

    void FixedUpdate()
    {
        canJump = CanJump();

        if (canJump)
        {
            if (Mathf.Abs(walkRaw) > 0.0f && myRigidbody.velocity.sqrMagnitude < maxSpeed * maxSpeed)
            {
                myRigidbody.AddForce(Quaternion.Euler(0f, heading, 0f) * ((Vector3.forward * walkRaw) * walkSpeed), ForceMode.Acceleration);
            }
        }
        else
        {
            if (Mathf.Abs(walkRaw) > 0.0f && myRigidbody.velocity.sqrMagnitude < maxSpeed * maxSpeed)
            {
                myRigidbody.AddForce(Quaternion.Euler(0f, heading, 0f) * ((Vector3.forward * walkRaw) * walkSpeed * 0.1f), ForceMode.Acceleration);
            }
        }
    }

    void OnCollisionEnter(Collision collision)
    {
        if(collision.gameObject.layer == Layers.Furnishing || collision.gameObject.layer == Layers.Target)
        { 
            if(canJump)
            {
                Jump();
            }
        }

        if (collision.gameObject.layer == Layers.Player && aiMode == AIMode.Pursuing)
        {
            collision.gameObject.SendMessageUpwards("Splatted", false);
            lastPursuitScore = playerController.score;
            aiMode = AIMode.Fleeing;
            footstepAudio.Stop();
            gameObject.SetLayerRecursively(Layers.Fleeing);
        }
    }

    void Splatted()
    {
        playerController.message = retorts[Random.Range(0, retorts.Length)];

        dignity -= 1f;

        if (dignity <= 0f && !wasKilled)
        {
            aiMode = AIMode.Fleeing;
            footstepAudio.Stop();
            gameObject.SetLayerRecursively(Layers.Fleeing);
            wasKilled = true;
            playerController.AwardKill(1);
            lastPursuitScore = playerController.score;
        }
    }

    private float VectorXZToAngle(Vector3 vector)
    {
        return (float)Mathf.Atan2(vector.x, vector.z) / Mathf.PI * 180.0f;
    }

    private static float ClampAngle(float angle, float min, float max)
    {
        if (angle < -360F)
            angle += 360F;
        if (angle > 360F)
            angle -= 360F;
        return Mathf.Clamp(angle, min, max);
    }

}
