﻿namespace StarterAssets
{
    using UnityEngine;
    using UnityEngine.InputSystem;

        [RequireComponent(typeof(CharacterController))]
    [RequireComponent(typeof(PlayerInput))]
    public class ThirdPersonController : MonoBehaviour
    {
                public float MoveSpeed = 2.0f;

                public float SprintSpeed = 5.335f;

                public float SpeedChangeRate = 10.0f;

                public float JumpHeight = 1.2f;

                public float Gravity = -15.0f;

                public float JumpTimeout = 0.50f;

                public float FallTimeout = 0.15f;

                public bool Grounded = true;

                public float GroundedOffset = -0.14f;

                public float GroundedRadius = 0.28f;

                public LayerMask GroundLayers;

                public Camera PlayerCamera;

                public float TopClamp = 70.0f;

                public float BottomClamp = -30.0f;

                public float CameraAngleOverride = 0.0f;

                public bool LockCameraPosition = false;

                public GameObject[] Items;

                private int currentItemIndex = 0;

                private float _cinemachineTargetYaw;

                private float _cinemachineTargetPitch;

                private float _speed;

                private float _verticalVelocity;

                private float _terminalVelocity = 53.0f;

                private float _jumpTimeoutDelta;

                private float _fallTimeoutDelta;

                private PlayerInput _playerInput;

                private CharacterController _controller;

                private StarterAssetsInputs _input;

                private Animator _animator;

                private int _animIDSpeed;

                private int _animIDGrounded;

                private int _animIDJump;

                private int _animIDFreeFall;

                private int _animIDMotionSpeed;

                private const float _threshold = 0.01f;

                private bool _hasAnimator;

                private bool IsCurrentDeviceMouse
        {
            get
            {
                return _playerInput != null && _playerInput.currentControlScheme == "KeyboardMouse";
            }
        }

                private void Awake()
        {
            if (PlayerCamera == null)
            {
                PlayerCamera = Camera.main;
            }
        }

                private void Start()
        {
            _cinemachineTargetYaw = PlayerCamera.transform.rotation.eulerAngles.y;
            _controller = GetComponent<CharacterController>();
            _input = GetComponent<StarterAssetsInputs>();
            _hasAnimator = TryGetComponent(out _animator);
            _playerInput = GetComponent<PlayerInput>();
            AssignAnimationIDs();
            _jumpTimeoutDelta = JumpTimeout;
            _fallTimeoutDelta = FallTimeout;
            ActivateItem(currentItemIndex);
        }

                private void Update()
        {
            _hasAnimator = TryGetComponent(out _animator);
            JumpAndGravity();
            GroundedCheck();
            Move();
            HandleItemSwitch();
        }

                private void LateUpdate()
        {
            CameraRotation();
        }

                private void AssignAnimationIDs()
        {
            _animIDSpeed = Animator.StringToHash("Speed");
            _animIDGrounded = Animator.StringToHash("Grounded");
            _animIDJump = Animator.StringToHash("Jump");
            _animIDFreeFall = Animator.StringToHash("FreeFall");
            _animIDMotionSpeed = Animator.StringToHash("MotionSpeed");
        }

                private void GroundedCheck()
        {
            Vector3 spherePosition = new Vector3(transform.position.x, transform.position.y - GroundedOffset,
                transform.position.z);
            //https://docs.unity3d.com/6000.4/Documentation/ScriptReference/Physics.CheckSphere.html
            Grounded = Physics.CheckSphere(spherePosition, GroundedRadius, GroundLayers,
                QueryTriggerInteraction.Ignore);
            if (_hasAnimator)
            {
                _animator.SetBool(_animIDGrounded, Grounded);
            }
        }

                private void CameraRotation()
        {
            if (_input.look.sqrMagnitude >= _threshold && !LockCameraPosition)
            {
                float deltaTimeMultiplier = IsCurrentDeviceMouse ? 1.0f : Time.deltaTime;
                _cinemachineTargetYaw += _input.look.x * deltaTimeMultiplier;
                _cinemachineTargetPitch += _input.look.y * deltaTimeMultiplier;
            }
            _cinemachineTargetYaw = ClampAngle(_cinemachineTargetYaw, float.MinValue, float.MaxValue);
            _cinemachineTargetPitch = ClampAngle(_cinemachineTargetPitch, BottomClamp, TopClamp);
            PlayerCamera.transform.rotation = Quaternion.Euler(_cinemachineTargetPitch + CameraAngleOverride,
                _cinemachineTargetYaw, 0.0f);
            transform.rotation = Quaternion.Euler(0.0f, _cinemachineTargetYaw, 0.0f);
        }

                private void Move()
        {
            float targetSpeed = _input.sprint ? SprintSpeed : MoveSpeed;
            if (_input.move == Vector2.zero) targetSpeed = 0.0f;
            float currentHorizontalSpeed = new Vector3(_controller.velocity.x, 0.0f, _controller.velocity.z).magnitude;
            float speedOffset = 0.1f;
            float inputMagnitude = _input.analogMovement ? _input.move.magnitude : 1f;
            if (currentHorizontalSpeed < targetSpeed - speedOffset ||
                currentHorizontalSpeed > targetSpeed + speedOffset)
            {
                _speed = Mathf.Lerp(currentHorizontalSpeed, targetSpeed * inputMagnitude,
                    Time.deltaTime * SpeedChangeRate);
                _speed = Mathf.Round(_speed * 1000f) / 1000f;
            }
            else
            {
                _speed = targetSpeed;
            }
            Vector3 inputDirection = new Vector3(_input.move.x, 0.0f, _input.move.y).normalized;
            Vector3 moveDirection = PlayerCamera.transform.right * inputDirection.x + PlayerCamera.transform.forward * inputDirection.z;
            moveDirection.y = 0f;
            _controller.Move(moveDirection.normalized * (_speed * Time.deltaTime) +
                             new Vector3(0.0f, _verticalVelocity, 0.0f) * Time.deltaTime);
            if (_hasAnimator)
            {
                _animator.SetFloat(_animIDSpeed, _speed);
                _animator.SetFloat(_animIDMotionSpeed, inputMagnitude);
            }
        }

                private void JumpAndGravity()
        {
            if (Grounded)
            {
                _fallTimeoutDelta = FallTimeout;
                if (_hasAnimator)
                {
                    _animator.SetBool(_animIDJump, false);
                    _animator.SetBool(_animIDFreeFall, false);
                }
                if (_verticalVelocity < 0.0f)
                {
                    _verticalVelocity = -2f;
                }
                if (_input.jump && _jumpTimeoutDelta <= 0.0f)
                {
                    _verticalVelocity = Mathf.Sqrt(JumpHeight * -2f * Gravity);
                    if (_hasAnimator)
                    {
                        _animator.SetBool(_animIDJump, true);
                    }
                }
                if (_jumpTimeoutDelta >= 0.0f)
                {
                    _jumpTimeoutDelta -= Time.deltaTime;
                }
            }
            else
            {
                _jumpTimeoutDelta = JumpTimeout;
                if (_fallTimeoutDelta >= 0.0f)
                {
                    _fallTimeoutDelta -= Time.deltaTime;
                }
                else
                {
                    if (_hasAnimator)
                    {
                        _animator.SetBool(_animIDFreeFall, true);
                    }
                }
                _input.jump = false;
            }
            if (_verticalVelocity < _terminalVelocity)
            {
                _verticalVelocity += Gravity * Time.deltaTime;
            }
        }

                private static float ClampAngle(float lfAngle, float lfMin, float lfMax)
        {
            if (lfAngle < -360f) lfAngle += 360f;
            if (lfAngle > 360f) lfAngle -= 360f;
            return Mathf.Clamp(lfAngle, lfMin, lfMax);
        }

                private void HandleItemSwitch()
        {
            float scroll = Input.GetAxis("Mouse ScrollWheel");
            if (scroll > 0f)
            {
                currentItemIndex = (currentItemIndex + 1) % Items.Length;
                ActivateItem(currentItemIndex);
            }
            else if (scroll < 0f)
            {
                currentItemIndex = (currentItemIndex - 1 + Items.Length) % Items.Length;
                ActivateItem(currentItemIndex);
            }
        }

                private void ActivateItem(int index)
        {
            for (int i = 0; i < Items.Length; i++)
            {
                if (Items[i] != null)
                {
                    Items[i].SetActive(i == index);
                    if (i == index)
                    {
                        // https://docs.unity3d.com/ScriptReference/Transform.SetParent.html
                        Items[i].transform.SetParent(PlayerCamera.transform);
                        // https://docs.unity3d.com/ScriptReference/Transform-localPosition.html
                        Items[i].transform.localPosition = new Vector3(0.4f, -0.3f, 0.7f);
                        // https://docs.unity3d.com/ScriptReference/Transform-localRotation.html
                        Items[i].transform.localRotation = Quaternion.identity;
                    }
                }
            }
        }

                private Vector2 lastLook;

                private Vector2 wiggleOffset;

                private void LateUpdate()
        {
            CameraRotation();
            UpdateItemWiggle();
        }
// Entferne doppelte LateUpdate-Methoden, falls vorhanden

                private void UpdateItemWiggle()
        {
            if (Items != null && Items.Length > 0 && Items[currentItemIndex] != null && Items[currentItemIndex].activeSelf)
            {
                // https://docs.unity3d.com/ScriptReference/Vector2.Lerp.html
                Vector2 lookDelta = _input.look - lastLook;
                lastLook = _input.look;
                wiggleOffset = Vector2.Lerp(wiggleOffset, lookDelta * 0.05f, 0.2f);
                Items[currentItemIndex].transform.localPosition = new Vector3(0.4f + wiggleOffset.x, -0.3f + wiggleOffset.y, 0.7f);
            }
        }

                private void OnFootstep()
        {
        }

                private void OnDrawGizmosSelected()
        {
            Color transparentGreen = new Color(0.0f, 1.0f, 0.0f, 0.35f);
            Color transparentRed = new Color(1.0f, 0.0f, 0.0f, 0.35f);
            if (Grounded) Gizmos.color = transparentGreen;
            else Gizmos.color = transparentRed;
            Gizmos.DrawSphere(
                new Vector3(transform.position.x, transform.position.y - GroundedOffset, transform.position.z),
                GroundedRadius);
        }
    }
}
