using UnityEngine;

namespace Shooter.Gameplay
{
    /// <summary>
    /// Камера, следящая за игроком сверху-сбоку (изометрический наклон). Плавно
    /// тянется за персонажем, «храповиком» продвигается вперёд по уровню (назад не
    /// откатывается), трясётся при выстрелах и попаданиях и умеет переключаться на
    /// общий план с боссом. Дополнительно вычисляет верхнюю и нижнюю границы видимой
    /// области на земле — ими пользуются враги (когда появляться) и фоновый блок.
    /// </summary>
    public class CameraControl : MonoBehaviour
    {
        public static CameraControl m_Current;

        [Header("Слежение за игроком")]
        [Tooltip("Удаление камеры от точки слежения")]
        public float FollowDistance = 80f;
        [Tooltip("Наклон камеры вниз, градусы")]
        public float CameraPitch = 40f;
        [Tooltip("Сглаживание смещения по горизонтали (0 — держать строго по центру)")]
        public float HorizontalDampen = 0.4f;
        [Tooltip("Скорость, с которой камера догоняет цель")]
        public float FollowSpeed = 5f;
        [Tooltip("На сколько камера держится впереди игрока по ходу уровня")]
        public float AdvanceOffset = 8f;
        [Tooltip("Стартовое смещение камеры вперёд от игрока")]
        public float StartZOffset = 10f;

        [Header("Тряска")]
        [Tooltip("Частота тряски по горизонтали")]
        public float ShakeFrequencyX = 50f;
        [Tooltip("Частота тряски по вертикали")]
        public float ShakeFrequencyY = 30f;
        [Tooltip("Ограничение амплитуды тряски")]
        public float ShakeMaxAmplitude = 0.5f;

        [Header("Режим боя с боссом")]
        [Tooltip("Цель-босс: если задана, камера берёт общий план игрока и босса")]
        public Transform m_BossTarget;
        [Tooltip("Доля смещения камеры к середине между игроком и боссом")]
        public float BossBlend = 0.5f;
        [Tooltip("Сглаживание по горизонтали в режиме босса")]
        public float BossHorizontalDampen = 0.6f;

        [Header("Ссылки")]
        public Camera m_MyCamera;
        [Tooltip("Фоновый блок, прижимаемый к нижней границе экрана")]
        public Transform m_BackBlock;
        [SerializeField]
        private Transform m_TargetPointTransform;

        public float m_MinZ = 0;

        [HideInInspector] public Transform m_Target;
        [HideInInspector] public Vector3 m_TargetPoint;
        [HideInInspector] public Vector3 m_CameraBottomPosition;
        [HideInInspector] public Vector3 m_CameraTopPosition;

        // Текущее направление взгляда камеры и состояние тряски.
        private Vector3 Direction;
        private float m_ShakeTimer;
        private float m_ShakeRadius = 1;

        void Awake()
        {
            m_Current = this;
        }

        void Start()
        {
            m_MyCamera = GetComponent<Camera>();

            // Камера начинает чуть впереди игрока.
            m_MinZ = PlayerChar.m_Current.transform.position.z + StartZOffset;
            m_CameraBottomPosition = new Vector3(0, 0, -100);
            m_CameraTopPosition = new Vector3(0, 0, -100);

            Direction = Quaternion.Euler(CameraPitch, 0, 0) * Vector3.forward;
            Vector3 targetPosition = PlayerChar.m_Current.transform.position;
            targetPosition.z = m_MinZ;
            targetPosition.x = HorizontalDampen * targetPosition.x;
            transform.position = targetPosition + -FollowDistance * Direction;
            transform.forward = Direction;
        }

        void Update()
        {
            // Тряска затухает к нулю.
            m_ShakeTimer = Mathf.Max(0, m_ShakeTimer - Time.deltaTime);
            float shakeAmount = Mathf.Clamp(m_ShakeTimer, 0, ShakeMaxAmplitude);
            float shakeY = Mathf.Cos(ShakeFrequencyY * Time.time) * shakeAmount;
            float shakeX = Mathf.Sin(ShakeFrequencyX * Time.time) * shakeAmount;
            Vector3 shakeOffset = new Vector3(m_ShakeRadius * shakeX, m_ShakeRadius * shakeY, 0);

            // «Храповик»: камера продвигается вперёд за игроком, но не откатывается назад.
            float playerFrontZ = PlayerControl.MainPlayerController.MyPlayerChar.transform.position.z + AdvanceOffset;
            if (playerFrontZ > m_MinZ)
                m_MinZ = playerFrontZ;

            Direction = Quaternion.Euler(CameraPitch, 0, 0) * Vector3.forward;
            Vector3 targetPosition = PlayerChar.m_Current.transform.position;
            targetPosition.z = m_MinZ;
            targetPosition.x = HorizontalDampen * targetPosition.x;

            if (m_BossTarget != null)
            {
                // Общий план: середина между игроком и боссом.
                targetPosition = PlayerChar.m_Current.transform.position + m_BossTarget.position;
                targetPosition = BossBlend * targetPosition;
                targetPosition.x = BossHorizontalDampen * targetPosition.x;
            }

            #region Опциональная фича: камера с захватом цели (Глава 4)
            //if (PlayerChar.m_Current.m_LockedTarget == null)
            //{
            //    Direction = Quaternion.Euler(40, 0, 0) * Vector3.forward;
            //    distance = 80;
            //}
            //else
            //{
            //    targetPosition = PlayerChar.m_Current.transform.position + PlayerChar.m_Current.m_LockedTarget.transform.position;
            //    targetPosition = 0.5f * targetPosition;
            //    Direction = Quaternion.Euler(60, 0, 0) * Vector3.forward;
            //    distance = 80;
            //}
            #endregion

            transform.position = Vector3.Lerp(transform.position, targetPosition + -FollowDistance * Direction, FollowSpeed * Time.deltaTime);
            transform.position += shakeOffset;
            transform.forward = Vector3.Lerp(transform.forward, Direction, FollowSpeed * Time.deltaTime);

            // Границы видимой области на земле (лучи через низ и верх центра экрана).
            m_CameraBottomPosition = ScreenPointToGround(0.5f * Screen.width, 0);
            m_BackBlock.position = m_CameraBottomPosition;

            m_CameraTopPosition = ScreenPointToGround(0.5f * Screen.width, Screen.height);
            m_TargetPointTransform.position = m_CameraTopPosition;
        }

        /// <summary>Проекция точки экрана (screenX, screenY) на землю — плоскость Y = 0.</summary>
        Vector3 ScreenPointToGround(float screenX, float screenY)
        {
            Ray ray = m_MyCamera.ScreenPointToRay(new Vector3(screenX, screenY, 0));
            new Plane(Vector3.up, Vector3.zero).Raycast(ray, out float dis);
            return ray.origin + dis * ray.direction;
        }

        /// <summary>Запускает тряску: t — длительность, r — амплитуда (радиус).</summary>
        public void StartShake(float t, float r)
        {
            if (m_ShakeTimer == 0 || m_ShakeRadius < r)
                m_ShakeRadius = r;

            m_ShakeTimer = t;
        }
    }
}
