using FishNet.Object;
using UnityEngine;
using UnityEngine.InputSystem;

namespace Players
{
    public sealed class PlayerMoving : NetworkBehaviour
    {
        [SerializeField] private float _moveSpeed = 5f;
        [SerializeField] private float _sprintMultiplier = 2f;
        [SerializeField] private float _slowMultiplier = 0.5f;
        [SerializeField] private CharacterController _characterController;
        [SerializeField] private InputActionReference _moveAction;
        [SerializeField] private InputActionReference _sprintAction;
        [SerializeField] private InputActionReference _slowAction;

        private Transform _cameraTransform;

        private void Awake()
        {
            Camera playerCamera = GetComponentInChildren<Camera>(true);
            if (playerCamera != null)
                _cameraTransform = playerCamera.transform;
        }

        private void OnEnable()
        {
            EnableAction(_moveAction);
            EnableAction(_sprintAction);
            EnableAction(_slowAction);
        }

        private void OnDisable()
        {
            DisableAction(_moveAction);
            DisableAction(_sprintAction);
            DisableAction(_slowAction);
        }
        
        private void Update()
        {
            if (!IsOwner)
                return;

            Vector2 moveInput = ReadMoveInput();
            float speedMultiplier = ReadSpeedMultiplier();

            Transform directionSource = _cameraTransform != null ? _cameraTransform : transform;
            Vector3 forward = Vector3.ProjectOnPlane(directionSource.forward, Vector3.up).normalized;
            Vector3 right = Vector3.ProjectOnPlane(directionSource.right, Vector3.up).normalized;
            Vector3 moveDirection = (right * moveInput.x + forward * moveInput.y).normalized;
            Vector3 offset = moveDirection * (_moveSpeed * speedMultiplier * Time.deltaTime);

            _characterController.Move(offset);
        }

        private Vector2 ReadMoveInput()
        {
            InputAction action = _moveAction != null ? _moveAction.action : null;
            return action != null ? action.ReadValue<Vector2>() : Vector2.zero;
        }

        private float ReadSpeedMultiplier()
        {
            bool isSprinting = IsActionPressed(_sprintAction);
            bool isSlowing = IsActionPressed(_slowAction);
            if (isSprinting == isSlowing)
                return 1f;

            return isSprinting ? _sprintMultiplier : _slowMultiplier;
        }

        private static bool IsActionPressed(InputActionReference actionReference)
        {
            InputAction action = actionReference != null ? actionReference.action : null;
            return action != null && action.IsPressed();
        }

        private static void EnableAction(InputActionReference actionReference)
        {
            InputAction action = actionReference != null ? actionReference.action : null;
            if (action != null && !action.enabled)
                action.Enable();
        }

        private static void DisableAction(InputActionReference actionReference)
        {
            InputAction action = actionReference != null ? actionReference.action : null;
            if (action != null && action.enabled)
                action.Disable();
        }
    }
}
