using UnityEngine;

namespace IndianOceanAssets.Engine2_5D
{
    /// <summary>
    /// 场景物件面向摄像机脚本（饥荒风格）v2。
    /// 让物体始终朝摄像机方向旋转，默认只绕 Y 轴（保持竖直不倒）。
    ///
    /// 抖动修复（v2）：
    /// 旧版平滑旋转用 Quaternion.Slerp(rot, target, speed * deltaTime)，
    /// 它永远无法真正到达目标（每帧只走剩余距离的几分之一），叠加 deltaTime
    /// 逐帧波动，会持续产生微小旋转 → 看起来在抖动。若摄像机本身也用 Lerp
    /// 跟随（CameraFollow 永不收敛），两者叠加更明显。
    ///
    /// 修复要点：
    /// 1. 指数平滑 t = 1 - exp(-speed * dt)，帧率无关，比 speed * dt 更稳定。
    /// 2. 剩余角度 ≤ snapAngle 时直接吸附到目标，杜绝永不收敛的微旋转。
    /// 3. 已吸附后，目标方向在 deadZone 内的微小漂移（摄像机/物件微抖）一律忽略，
    ///    只有方向变化超过 deadZone 才重新吸附 → 摄像机静止时物件彻底不动。
    ///
    /// 用法：挂到需要面向摄像机的精灵/物件上即可。
    /// </summary>
    public class BillboardSprite : MonoBehaviour
    {
        [Tooltip("只绕Y轴旋转（饥荒风格，保持竖直不倒）。关闭则完全面向摄像机。")]
        [SerializeField] private bool lockYAxis = true;

        [Tooltip("平滑旋转（过渡），关闭则瞬间转向")]
        [SerializeField] private bool smoothRotation = false;

        [Tooltip("平滑旋转速度（越大转得越快）")]
        [SerializeField] private float rotationSpeed = 8f;

        [Tooltip("剩余角度小于此值时直接吸附到目标，避免永不收敛的微旋转（主要抖动来源）。")]
        [SerializeField] private float snapAngle = 0.5f;

        [Tooltip("已吸附后，目标方向在此角度内的微小漂移视为噪声忽略（过滤摄像机微抖）。")]
        [SerializeField] private float deadZone = 0.2f;

        private Camera _mainCamera;
        private Transform _camTransform;
        private Quaternion _convergedRot;
        private bool _hasConverged;

        private void Start()
        {
            _mainCamera = Camera.main;
            if (_mainCamera != null)
                _camTransform = _mainCamera.transform;
        }

        private void LateUpdate()
        {
            if (_camTransform == null)
            {
                // 摄像机丢失时重新获取（场景切换等情况）
                _mainCamera = Camera.main;
                if (_mainCamera != null)
                    _camTransform = _mainCamera.transform;
                if (_camTransform == null) return;
            }

            Vector3 dir = _camTransform.position - transform.position;

            if (lockYAxis)
                dir.y = 0f; // 保持竖直

            if (dir.sqrMagnitude < 0.0001f) return;

            Quaternion targetRot = Quaternion.LookRotation(dir);

            if (!smoothRotation)
            {
                transform.rotation = targetRot;
                _convergedRot = targetRot;
                _hasConverged = true;
                return;
            }

            // ---- 平滑旋转 ----
            float angleToTarget = Quaternion.Angle(transform.rotation, targetRot);

            if (angleToTarget <= snapAngle)
            {
                // 已接近目标。仅当目标相对上次吸附转了超过 deadZone 才重新吸附，
                // 否则视为噪声保持不动（摄像机静止时物件不抖）
                if (!_hasConverged || Quaternion.Angle(targetRot, _convergedRot) > deadZone)
                {
                    transform.rotation = targetRot;
                    _convergedRot = targetRot;
                    _hasConverged = true;
                }
            }
            else
            {
                // 还差较远，指数平滑趋近（帧率无关，比 speed*deltaTime 更稳）
                float t = 1f - Mathf.Exp(-rotationSpeed * Time.deltaTime);
                transform.rotation = Quaternion.Slerp(transform.rotation, targetRot, t);
                _hasConverged = false;
            }
        }
    }
}
