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

[RequireComponent(typeof(Rigidbody))]
public class TestMoveTerrain : MonoBehaviour {

    public float Speed;
    private float m_vertVel;

	// Use this for initialization
	void Start ()
    {
        GetComponent<Rigidbody>().velocity = transform.forward * 1;
	}
	
	// Update is called once per frame
	void FixedUpdate ()
    {
        float _distThisUpdate = GetComponent<Rigidbody>().velocity.magnitude * Time.fixedDeltaTime;

        // Create a hit result
        RaycastHit hit;

        Vector3 _startPos;
        Vector3 _dir;

        // Because RaycastHit is a struct
        bool gotHit = false;

        // Create a mask that only detects default (terrain) and environmental (prefab) objects
        LayerMask _mask = LayerMask.GetMask("Default", "Environment");

        Debug.DrawRay(transform.position, transform.forward, Color.black);

        // FRONT CHECK //
        #region
        // Start positon is slightly above center so that we don't accidentally clip the floor
        _startPos = transform.position + (transform.up * 0.1f);

        // We'll be raycasting forward
        _dir = transform.forward;

        // Show where we raytrace
        Debug.DrawLine(_startPos, _startPos + _dir * _distThisUpdate, Color.red);

        // Is something in front of us?
        gotHit = Physics.Raycast(_startPos, _dir, out hit, _distThisUpdate, _mask);

        // If we got a hit and the angle of the hit is over 90 degrees, destroy the object
        if (gotHit)
            if (Vector3.Angle(transform.up, hit.normal) > 120)
            {
                Debug.Log(Vector3.Angle(transform.forward, hit.normal).ToString() + " degrees");
                Destroy(gameObject);
            }
        #endregion

        // DOWN CHECK //
        #region
        // We only change the direction for this check, going down
        _dir = -transform.up;

        // Show where we raytrace
        Debug.DrawLine(_startPos, _startPos + _dir * 0.7f, Color.blue);

        // If not, below us?
        if (!gotHit)
            gotHit = Physics.Raycast(_startPos, _dir, out hit, 0.7f, _mask);
        #endregion

        // DOWN BACK CHECK //
        #region
        // The starting position is slightly in front and slightly below. We are checking for a "cliff" face below us
        _startPos = transform.position + (transform.forward * 0.1f) + (-transform.up * 0.1f);

        // Direction is backwards
        _dir = -transform.forward;

        // Show where we raytrace
        Debug.DrawLine(_startPos, _startPos + _dir * 0.2f, Color.green);

        // If not, below AND behind us?
        if (!gotHit)
            // If we hit something below and behind us
            gotHit = Physics.Raycast(_startPos, _dir, out hit, 0.2f, _mask);
        #endregion

        // If we hit anything...
        if (gotHit)
        {
            Debug.DrawLine(hit.point, hit.point + hit.normal);

            Vector3 lookAt = Vector3.Cross(transform.right, hit.normal);

            //lookAt = lookAt.x < 0 ? -lookAt : lookAt;

            // Rotate from our current up to the normal we hit
            transform.LookAt(transform.position + lookAt, hit.normal);

            // Change our velocity to the new forward times our current magnitude
            GetComponent<Rigidbody>().velocity = transform.forward * Speed;

            // Set our position to the hit point
            transform.position = hit.point;

            m_vertVel = 0;
        }
        // Otherwise, handle falling/floating behaviors
        else
        {
            m_vertVel += GetComponent<Rigidbody>().useGravity ? GetComponent<Rigidbody>().mass * Time.fixedDeltaTime : 0;
            GetComponent<Rigidbody>().velocity = transform.forward * Speed + Vector3.down * m_vertVel;
        }
    }
}
