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

public class Poltergeist_Script : MonoBehaviour {


    enum GhostState { Patrolling, Chasing, Seeking}
    GameObject kitty;

    //private data
    NavMeshAgent myNavAgent;
    GhostState myState;
    bool canSeeKitty;
    List<GameObject> liftedObjects;
    

    //public data
    public float mySpeed = 1.0f;
    public float viewAngle = 60.0f;
    public float proximityCheck = 4.5f;
    public float randomNavRange = 10.0f;
    public float upForce = 10.0f;

    void Awake ()
    {
        kitty = GameObject.Find("Kitty");
        myNavAgent = GetComponent<NavMeshAgent>();
        myState = GhostState.Patrolling;
        myNavAgent.SetDestination(transform.position);
    }
	
	void FixedUpdate ()
    {
        canSeeKitty = TrySeeKitty();
        if (myNavAgent.velocity.magnitude > 0.0f)
        {
            transform.rotation = Quaternion.LookRotation(myNavAgent.velocity, Vector3.up);
        }
        //Debug.Log(myState);
        switch (myState)
        {
            case GhostState.Patrolling:
                {
                    if (canSeeKitty)
                    {
                        StartChasing();
                    }
                    else
                    {
                        Patrol();
                    }
                    break;
                }
            case GhostState.Chasing:
                {
                    if (canSeeKitty)
                    {
                        myNavAgent.SetDestination(kitty.transform.position);//actual chasing
                    }
                    else
                    {
                        StartCoroutine(Seek());
                    }
                    break;
                }
            case GhostState.Seeking:
                if (canSeeKitty)
                {
                    StartChasing();
                }
                break;
            default:
                Debug.LogAssertion("unknown poltergeist state");
                break;
        }
	}
    void OnTriggerStay(Collider other)
    {
        if (other.tag == "Trash")
        {
            Rigidbody otherBody = other.GetComponent<Rigidbody>();
            otherBody.AddForce(new Vector3(0, upForce, 0));
        }
    }
    void OnTriggerEnter(Collider other)
    {
        if (other.gameObject == kitty)
        {
            kitty.GetComponent<CatHealth_Script>().TakeDamage(3);
        } else
        if (other.tag == "Trash")
        {
            liftedObjects.Add(other.gameObject);
        }
    }
    void OnTriggerExit(Collider other)
    {
        if (other.tag == "Trash")
        {
            liftedObjects.Remove(other.gameObject);
        }
    }

    bool TrySeeKitty()
    {
        RaycastHit hit;
        Vector3 toKittyVector = kitty.transform.position - transform.position;
        float toKittyAngle = Vector3.Angle(new Vector3(transform.forward.x, 0.0f, transform.forward.z), new Vector3(toKittyVector.x, 0.0f, toKittyVector.z));//may have problems when blinky is standing still
        if (Physics.Raycast((transform.position), toKittyVector, out hit) && (hit.collider.gameObject == kitty) && (toKittyAngle < viewAngle))//tried to move 2nd and 3rd cond-s to this line from separate 'if'
        {
            return true;
        }
        return false;
    }
    void Patrol()
    {
        if (myNavAgent.remainingDistance < proximityCheck)
        {
            Vector3 point;
            if (RandomPoint(transform.position, randomNavRange, out point))
            {
                myNavAgent.SetDestination(point);
                myNavAgent.Resume();
            }
        }
        //else just moving to the destination 
    }
    void StartChasing()
    {
        StopCoroutine(Seek());
        myNavAgent.speed = mySpeed * 1.5f;
        myNavAgent.Resume();
        myState = GhostState.Chasing;
    }
    IEnumerator Seek()
    {
        myState = GhostState.Seeking;
        myNavAgent.speed = mySpeed;
        while (myNavAgent.remainingDistance > proximityCheck)
        {
            yield return new WaitForEndOfFrame(); //going to the last known position of the cat 
        }
        myNavAgent.Stop();
        float rotDone = 0.0f;
        float rotStep = 0.5f;
        while (rotDone < 60.0f)//REWRITE IT FFS
        {
            transform.Rotate(Vector3.up, -rotStep);
            rotDone += rotStep;
            yield return new WaitForEndOfFrame();
        }
        while (rotDone < 180.0f)
        {
            transform.Rotate(Vector3.up, rotStep);
            rotDone += rotStep;
            yield return new WaitForEndOfFrame();
        }
        while (rotDone < 240.0f)
        {
            transform.Rotate(Vector3.up, -rotStep);
            rotDone += rotStep;
            yield return new WaitForEndOfFrame();
        }
        myNavAgent.speed = mySpeed;
        myState = GhostState.Patrolling;
        yield return new WaitForEndOfFrame();
    }
    bool RandomPoint(Vector3 center, float range, out Vector3 result)
    {
        for (int i = 0; i < 30; i++)
        {
            Vector3 randomPoint = center + Random.insideUnitSphere * range;
            NavMeshHit hit;
            if (NavMesh.SamplePosition(randomPoint, out hit, 1.0f, NavMesh.AllAreas))
            {
                result = hit.position;
                return true;
            }
        }
        result = Vector3.zero;
        return false;
    }
    public void Investigate(Vector3 newDestination)
    {
        //setting new destination
        myNavAgent.SetDestination(newDestination);
        //well, investigating...
        StartCoroutine(Seek());
    }

}
