﻿using JLGames.RocketDriver.Actions.Extensions;
using UnityEngine;

namespace JLGames.RocketDriver.Actions.Utils
{
    public static class CameraUtil
    {
        #region LookAt

        /// <summary>
        /// Pan the camera position so that the target is displayed in the center of the camera
        /// 平移相机位置，使目标显示在相机中心
        /// </summary>
        /// <returns>返回终点位置</returns>
        /// <param name="camera">Camera.</param>
        /// <param name="target">Target.</param>
        public static Vector3 PostionLookAt(Camera camera, Transform target)
        {
            var camNormalRay = camera.ViewportPointToRay(new Vector3(0.5f, 0.5f));
            return target.position -
                   Vector3.Project((target.position - camera.transform.position), camNormalRay.direction);
        }

        /// <summary>
        /// Rotate the camera so that the target is displayed in the center of the camera
        /// 旋转相机，使目标显示在相机中心
        /// </summary>
        /// <returns>返回终点旋转结果</returns>
        /// <param name="camera">Camera.</param>
        /// <param name="target">Target.</param>
        public static Quaternion RotationLookAt(Camera camera, Transform target)
        {
            var ti = camera.transform.CloneTransform();
            camera.transform.LookAt(target);
            var result = camera.transform.rotation;
            camera.transform.UpdateTransform(ti);
            return result;
        }

        /// <summary>
        /// Rotate the camera so that the target is displayed in the center of the camera, and return euler angles.
        /// 旋转相机，使目标显示在相机中心, 返回旋转欧拉角
        /// </summary>
        /// <returns>返回终点旋转结果，欧拉角</returns>
        /// <param name="camera">Camera.</param>
        /// <param name="target">Target.</param>
        public static Vector3 RotationEulerLookAt(Camera camera, Transform target)
        {
            return RotationLookAt(camera, target).eulerAngles;
        }

        #endregion

        #region Zoom

        /// <summary>
        /// Fits the size of the zoom for orthographic.
        /// 要求相机为正交视角
        /// </summary>
        /// <returns>The zoom for orthographic size.</returns>
        /// <param name="camera">Camera.</param>
        /// <param name="target">Target.</param>
        public static float FitZoomForOrthographicSize(Camera camera, Transform target)
        {
            if (!camera.orthographic)
            {
                return 0;
            }

            return target.GetBounds().extents.magnitude;
        }

        /// <summary>
        /// Fits the zoom for fieldofview.
        /// 要求相机为透视视角
        /// </summary>
        /// <returns>The zoom for fieldofview.</returns>
        /// <param name="camera">Camera.</param>
        /// <param name="target">Target.</param>
        public static float FitZoomForFieldofview(Camera camera, Transform target)
        {
            if (camera.orthographic)
            {
                return 0;
            }

            var extends = target.GetBounds().extents.magnitude;
            var dist = (target.position - camera.transform.position).magnitude;
            return Mathf.Atan2(extends, dist) * Mathf.Rad2Deg * 2;
        }

        /// <summary>
        /// Fits the zoom for position.
        /// 要求相机为透视视角
        /// </summary>
        /// <returns>The zoom for position.</returns>
        /// <param name="camera">Camera.</param>
        /// <param name="target">Target.</param>
        public static Vector3 FitZoomForPosition(Camera camera, Transform target)
        {
            if (camera.orthographic)
            {
                return Vector3.zero;
            }

            var extends = target.GetBounds().extents.magnitude;
            var dist = extends / Mathf.Tan(Mathf.Deg2Rad * camera.fieldOfView / 2);
            //Debug.Log("fov: " + camera.fieldOfView + ", extends: " + extends + ", dist: " + dist);
            return target.position - (target.position - camera.transform.position).normalized * dist;
        }

        #endregion
    }
}