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

//using UnityEditor;

namespace Arugula.Prototypical
{
    public class ObserverCamera : MonoBehaviour, ICameraSystem
    {
        public enum UpdateMode
        {
            Update, LateUpdate, FixedUpdate, BeforeRender
        }

        public UpdateMode updateMode;
        public Transform target;
        public LayerMask occlusionMask;
        public float safeRadius = 0.5f;
        public float minDistance = 0.5f;
        public float nominalDistance = 4f;
        public float nominalTilt = -15;
        public float nominalPan = 0;

        [Range(1f, 40f)]
        public float dampener = 14;

        public Transform pan;
        public Transform tilt;
        public Transform dolly;
        public Camera cam;


        #region internal
        private void Start()
        {
            if (updateMode == UpdateMode.BeforeRender)
                Application.onBeforeRender += OnBeforeRender;
        }

        private void OnBeforeRender()
        {
            Apply();
        }

        private void Update()
        {
            if (updateMode == UpdateMode.Update)
                Apply();
        }

        private void LateUpdate()
        {
            if (updateMode == UpdateMode.LateUpdate)
                Apply();
        }

        private void FixedUpdate()
        {
            if (updateMode == UpdateMode.FixedUpdate)
                Apply();
        }
        #endregion



        public void Apply()
        {
            if (target == null)
                return;

            float goalDistance = -dolly.localPosition.z;
            float tiltGoal = nominalTilt;

            transform.position = Vector3.Lerp(transform.position, target.position, Time.deltaTime * dampener);

            Ray ray = new Ray(target.position, cam.transform.position - target.position);

            RaycastHit hit = new RaycastHit();

            if (Physics.SphereCast(ray, safeRadius, out hit, nominalDistance, occlusionMask, QueryTriggerInteraction.Ignore))
            {
                goalDistance = Vector3.Distance(hit.point, ray.origin);
                if (goalDistance < minDistance)
                {
                    goalDistance = minDistance;
                }
                else
                {

                }
            }
            else
            {
                goalDistance = nominalDistance;
                tiltGoal = nominalTilt;
            }

            dolly.localPosition = Vector3.Lerp(dolly.localPosition, Vector3.back * goalDistance, Time.deltaTime * dampener);
            tilt.localRotation = Quaternion.Slerp(tilt.localRotation, Quaternion.Euler(tiltGoal, 0, 0), Time.deltaTime * dampener);
            pan.localRotation = Quaternion.Slerp(pan.localRotation, Quaternion.Euler(0, nominalPan, 0), Time.deltaTime * dampener);
        }

        public void SetTarget(Transform t)
        {
            target = t;
        }

        public void SetTarget(CameraTarget t)
        {
            if (t == null)
                target = null;
            else
                target = t.transform;
        }
    }

}
