using UnityEngine;
using System.Collections;

public class PlayerController : MonoBehaviour 
{
    public bool allowMovement = true;
    public float turnSpeed = 30f;
    public float walkSpeed = 15f;
    public float maxSpeed = 10f;
    public float baseThrowStrength = 100f;
    public Transform eyes;
    public Rigidbody myRigidbody;
    public AudioClip hitSound;
    public WalkGuide[] walkGuides;
    public float launchPitch;
    public float fireChargeTime;
    public float maxChargeTime;
    public float dignity;
    public float jumpForce;
    public bool isCrouching;
    public int score;
    public int breakagePoints;
    public bool gameOver;
    public bool isWinner;
    public string message;
    public CapsuleCollider capsuleCollider;

    //public FoodProjectile projectileControllerPrefab;
    //public GameObject projectileAvatarPrefab;
    //public GameObject heldObject;
    //public Rigidbody heldRigidbody;
    public Grabber grabber;

    private float walkRaw;
    private float strafeRaw;
    private float heading;
    private float pitch;
    private bool canJump;

    private int[] kills = new int[] { 0, 0, 0, 0, 0 };
    private int[] baseScores = new int[] { 50, 200, 500, 1000, 5000 };

    public void AwardKill(int mobType)
    {
        kills[mobType]++;
        score += baseScores[mobType];
    }

    public int GetKills(int mobType)
    {
        return kills[mobType];
    }

    public void AwardBreakagePoints(int points)
    {
        breakagePoints += points;
        score += points;
    }

    private void FireProjectile()
    {
        float totalStrength = baseThrowStrength * fireChargeTime;

        if (grabber.heldRigidbody != null)
        {
            var launchAngle = Quaternion.Euler(launchPitch - pitch, heading, 0f);
            var launchForce = launchAngle * new Vector3(0f, 0f, totalStrength) + myRigidbody.velocity;
            grabber.LaunchHeld(launchForce);
        }
    }

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

    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, capsuleCollider.radius + 0.01f, 0f), Vector3.down), capsuleCollider.radius, 0.021f, Layers.GetMask(Layers.Floor) | Layers.GetMask(Layers.Furnishing));
    }

	void Update () 
    {
        if (allowMovement)
        {
            walkRaw = Input.GetAxis("Walk");
            strafeRaw = Input.GetAxis("Strafe");
            float turnRaw = Input.GetAxis("Turn");
            float pitchRaw = -Input.GetAxis("Pitch");

            if (walkRaw > 0f)
            {
                foreach (var guide in walkGuides)
                {
                    turnRaw += guide.GetCorrection() * walkRaw;
                }
            }

            if (grabber.heldRigidbody != null)
            {
                if (Input.GetButton("Throw"))
                {
                    fireChargeTime = fireChargeTime.AddToMaximum(Time.deltaTime, maxChargeTime);
                }
                if (fireChargeTime > 0f && Input.GetButtonUp("Throw"))
                {
                    FireProjectile();
                    fireChargeTime = 0f;
                    //projectileAvatarPrefab = null;
                }
            }

            if (Input.GetButtonDown("Jump"))
            {
                if (canJump)
                {
                    Jump();
                }
            }

            isCrouching = Input.GetButton("Crouch");

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

            if (Mathf.Abs(pitchRaw) > 0.0f)
            {
                pitch += turnSpeed * pitchRaw;
            }

            pitch = ClampAngle(pitch, -80f, 80f);
            heading = ClampAngle(heading, -360f, 360f);

            Quaternion xQuaternion = Quaternion.AngleAxis(heading, Vector3.up);
            Quaternion yQuaternion = Quaternion.AngleAxis(pitch, Vector3.left);

            transform.localRotation = xQuaternion;
            eyes.localRotation = yQuaternion;

            if(isCrouching && capsuleCollider.height > 1f)
            {
                capsuleCollider.height = capsuleCollider.height.SubtractToMinimum(Time.deltaTime * 2f, 1f);
                Camera.main.transform.localPosition = new Vector3(0f, Mathf.Lerp(1f, 1.8f, capsuleCollider.height - 1f), 0f);
            }
            if(!isCrouching && capsuleCollider.height < 2f)
            {
                capsuleCollider.height = capsuleCollider.height.AddToMaximum(Time.deltaTime * 2f, 2f);
                Camera.main.transform.localPosition = new Vector3(0f, Mathf.Lerp(1f, 1.8f, capsuleCollider.height - 1f), 0f);
            }
        }
        else
        {
            walkRaw = 0f;
            strafeRaw = 0f;
        }

        if(dignity <= 0)
        {
            allowMovement = false;
            gameOver = true;
        }

        if(kills[0] >= Customer.customerCount && Customer.customerCount > 0)
        {
            allowMovement = false;
            gameOver = true;
            isWinner = true;
        }
    }

    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);
            }

            if (Mathf.Abs(strafeRaw) > 0f && myRigidbody.velocity.sqrMagnitude < maxSpeed * maxSpeed)
            {
                myRigidbody.AddForce(Quaternion.Euler(0f, heading, 0f) * ((Vector3.right * strafeRaw) * 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);
            }

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

    void Awake()
    {
        grabber = GetComponentInChildren<Grabber>();
    }

    void Splatted()
    {
        OneShot3DAudio.PlayClipAtPoint(hitSound, transform.position);

        dignity -= 1f;
    }
    
    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);
    }
}
