﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Photon.Pun;
using Cinemachine;

public class CameraController : MonoBehaviourPunCallbacks
{
    [Header("Camera Components")]
	public CinemachineVirtualCamera cinacam;
    public SpectatorController spectatorController;

    [Header("Kart Control Data")]
    [ReadOnly]
	public KartController kartController;

    public bool toggleCinemaCam;

    //[HideInInspector]
    public bool spectatorOverride = false;
    public bool forceDisableFollow = false;
    public bool enableFollow;

    // [HideInInspector]
    public Vector3 camFollowOffset = new Vector3 (0f, 2f, -10f);
    public float camPivotSpeed = 5f, camSmoothTime = 5f, camFollowSpeed = 5f;
    private Vector3 camVelocity = Vector3.zero;


    void Update()
    {
        if (!forceDisableFollow && !spectatorController.isActiveAndEnabled)
        {
		    if (!kartController)
            {
			    SetTarget ();
		    }
            if (!toggleCinemaCam)
            {
                UpdateCameraPositionAndRotation(kartController, false);
            }
        }
    }

	void SetTarget () {
		KartController[] karts = FindObjectsOfType<KartController> ();
		KartController me = null;
		if (karts.Length > 0) {
			foreach (KartController k in karts) {
				if (k.photonView && k.photonView.IsMine && PhotonNetwork.IsConnected) {
					me = k;
					break;
				} else if (!k.photonView || !PhotonNetwork.IsConnected) {
					me = k;
					break;
				}
			}
		}

		if (me) {
			kartController = me;
            if (toggleCinemaCam) {
                cinacam.Follow = me.transform.GetChild(0);
                cinacam.LookAt = me.transform;
            }
			kartController.boostVisual = transform.GetComponentInChildren<ParticleSystem> ();
        }
        /*
        else
        {
            //Debug.LogError("No player was found. Did you forget to add one to the scene?");
            forceDisableFollow = true;
        }
        */
	}

	public void MoveToSpecificTarget(KartController me)
	{
		kartController = me;
        if (toggleCinemaCam) {
            cinacam.Follow = kartController.transform.GetChild(0);
            cinacam.LookAt = kartController.transform;
        }
		kartController.boostVisual = transform.GetComponentInChildren<ParticleSystem>();
		//kController.camPivot = GameObject.FindGameObjectWithTag("Camera Pivot").transform;
		//target = pBase.camPivot;
		/*
		if (!collision.myCam)
		{
			collision.Initialize(GetComponent<Camera>());
			collision.UpdateCameraClipPoints(transform.position, transform.rotation, ref collision.adjustedCameraClipPoints);
			collision.UpdateCameraClipPoints(destination, transform.rotation, ref collision.desiredCameraClipPoints);
		}
		*/
	}

    public bool FindLegalFollowTarget()
    {
        KartController[] karts = FindObjectsOfType<KartController>();
        if (karts.Length > 0)
        {
            foreach (KartController k in karts)
            {
                if (k.photonView && k.photonView.IsMine && PhotonNetwork.IsConnected)
                {
                    kartController = k;
                    return true;
                }
                else if (!k.photonView || !PhotonNetwork.IsConnected)
                {
                    kartController = k;
                    return true;
                }
            }
        }
        return false;
    }

    // Returns a position from a target transform using an given offset vector
    public Vector3 ReturnOffsetPositionAtVector(Transform targetTransform, Vector3 targetOffset) {

        // Derive a return position by adding the product of each directional vector and their respective offset values to the target position
        Vector3 returnPosition = targetTransform.position + (targetTransform.right * targetOffset.x) + (targetTransform.up * targetOffset.y) + (targetTransform.forward * targetOffset.z);

        // Return the derived position
        return returnPosition;
    }

    public void UpdateCameraPositionAndRotation(KartController target, bool snap)
    {
        // Disables the following behaviors if we were unable to find a legal target
        if (forceDisableFollow)
        {
            // Recursively checks for a new target if we have none
            if (!FindLegalFollowTarget())
            {
                return;
            }
        }


        if (enableFollow)
        {
            // Retrieve the position of the object we are following
            Vector3 lookTarget = kartController.transform.position;
            // Get our current camera position
            Vector3 currentPos = transform.position;
            // Get the desired distance from our camera to our player
            float followDistance = camFollowOffset.magnitude;
            // Get the transform of the Normal object inside the kart, which controls kart rotations
            Transform followTransform = kartController.gameObject.transform.GetChild(0).transform;

            // Retrieve the "ideal" location for our camera based on the transforms of the kart
            Vector3 targetPosition = ReturnOffsetPositionAtVector(followTransform, camFollowOffset);

            // Only move if we are not currently on target
            if (transform.position != targetPosition)
            {
                // Only move smoothly if we are not currently snapping to target
                if (!snap)
                {
                    // Move the camera smoothly into position
                    transform.position = Vector3.SmoothDamp(currentPos, targetPosition, ref camVelocity, camSmoothTime, camFollowSpeed);
                }
                // Otherwise, snap to the target
                transform.position = targetPosition;
            }

            // Store a reference to our current rotation in Euler
            Vector3 currentRotation = new Vector3(transform.rotation.x, transform.rotation.y, transform.rotation.z);

            // Check if the angle between our current and target look position is
            // different from our current camera rotation
            if (Vector3.ClampMagnitude(lookTarget - transform.position, 1f) - Vector3.ClampMagnitude(currentRotation, 1f) != Vector3.zero)
            {
                Debug.Log("Is this running?");
                // Only lerp the camera to the currect rotation if we are not snapping to target
                if (!snap)
                {
                    // Use Spherical Interpolation to move from our current rotation to the target rotation over time
                    Quaternion.Slerp(transform.rotation, Quaternion.Euler(lookTarget), camPivotSpeed * Time.unscaledDeltaTime);
                }
                // Otherwise snap to target
                transform.LookAt(lookTarget);
            }
        }
    }
}
