using System;
using UnityEngine;

namespace CharacterController
{
    [Serializable]
    public struct PlayerStats
    {
        #region Run
        [field: SerializeField, Tooltip("How fast should the player run?")]
        public float TargetRunSpeed { get; private set; }

        [field: SerializeField, Tooltip("How quickly should the player start moving, in seconds?")]
        public float Acceleration { get; private set; }
        
        [field: SerializeField, Tooltip("How quickly should the player start moving, in seconds, while airbourne?")]
        public float AirAcceleration { get; private set; }
        
        [field: SerializeField, Tooltip("How quickly should the player start moving, in seconds, while airbourne at the peak of your jump?")]
        public float PeakAcceleration { get; private set; }

        [field: SerializeField, Tooltip("How quickly should the player stop moving, in seconds?")]
        public float Deceleration { get; private set; }
        
        [field: SerializeField, Tooltip("How quickly should the player stop moving, in seconds, while airborne?")]
        public float AirDeceleration { get; private set; }
        
        [field: SerializeField, Tooltip("How quickly should the player stop moving, in seconds, while airborne at the peak of your jump?")]
        public float PeakDeceleration { get; private set; }

        [field: SerializeField, Tooltip("How quickly should the player turn, in seconds?")]
        public float TurnSpeed { get; private set; }
        
        [field: SerializeField, Tooltip("How quickly should the player turn, in seconds, while airborne?")]
        public float TurnSpeedAir { get; private set; }

        [field: SerializeField, Tooltip("What is the player's maxiumum horizontal speed?")]
        public float MaxHorizontalSpeed { get; private set; }
        #endregion

        #region Jump
        [field: SerializeField, Tooltip("What is the player's maxiumum vertical speed?")]
        public float MaxVerticalSpeed { get; private set; }

        [field: SerializeField, Tooltip("How high should the player jump when they tap the jump button?")]
        public float JumpHeightMin { get; private set; }

        [field: SerializeField, Tooltip("How high should the player jump when they hold the jump button?")]
        public float JumpHeightMax { get; private set; }
        
        [field: SerializeField, Tooltip("How many seconds should the player hold the jump button for to achieve max height?")]
        public float TimeForMaxJump { get; private set; }

        [field: SerializeField, Tooltip("How long should the jump take to reach the apex?")]
        public float JumpTime { get; private set; }

        [field: SerializeField,
                Tooltip("What should we multiply the gravity by when the player is at the peak of their jump?")]
        public float JumpPeakGravity { get; private set; }

        [field: SerializeField, Tooltip("At what speed should the player be moving when we apply the peak gravity?")]
        public float JumpPeakThreshold { get; private set; }

        [field: SerializeField, Tooltip("What should we multiply the gravity by when the player is falling?")]
        public float FallGravity { get; private set; }
        
        [field: SerializeField, Tooltip("Which layers count as the \"floor\"?")]
        public LayerMask GroundLayers { get; private set; }

        #endregion
        
        #region Grace
        [field: SerializeField,
                Tooltip("For how many seconds after falling off a ledge should the player be able to jump?")]
        public float CoyoteTime { get; private set; }

        [field: SerializeField,
                Tooltip(
                    "For how many seconds after pressing the jump button should the game register a jump on landing?")]
        public float InputBuffer { get; private set; }
        #endregion

        #region WallJump

        [field: SerializeField, Tooltip("Where should the player check for a wall?")]
        public Vector2 WallJumpCheckOffset { get; private set; }
        
        [field: SerializeField, Tooltip("How big should the wall jump check be?")]
        public float WallJumpCheckSize { get; private set; }
        
        [field: SerializeField, Tooltip("Which layers count as a wall?")]
        public LayerMask WallCheckLayers { get; private set; }
        
        [field: SerializeField, Tooltip("How fast should the player move after a wall jump? (climbing upwards)")]
        public Vector2 WallJumpForce { get; private set; }
        
        [field: SerializeField, Tooltip("How fast should the player move after a wall leap? (leaping across)")]
        public Vector2 WallLeapForce { get; private set; }
        
        [field: SerializeField, Tooltip("For how many seconds should the player stick to the wall before sliding down?")]
        public float WallStickTime { get; private set; }

        [field: SerializeField, Tooltip("How fast should the player fall while pushing into a wall?")]
        public float WallSlideSpeed { get; private set; }
        
        [field: SerializeField, Tooltip("For how long do we disable the player input while wall jumping?")]
        public float WallJumpPlayerInputTime { get; private set; }
        
        #endregion
        
        [field: SerializeField, HideInInspector]
        public float JumpForce { get; private set; }
        
        [field: SerializeField, HideInInspector]
        public float Gravity { get; private set; }
        public void CalculateForces()
        {
            //Calculate gravity strength using the formula (gravity = 2 * jumpHeight / timeToJumpApex^2) 
            Gravity = -(2 * JumpHeightMax) / (JumpTime * JumpTime);

            //Calculate jumpForce using the formula (initialJumpVelocity = gravity * timeToJumpApex)
            JumpForce = Mathf.Abs(Gravity) * JumpTime;
        }
    }
}