using Intrepid.Core.TimeControl;
using Intrepid.Structures;
using Intrepid.Utilities;
using UnityEngine;

namespace Intrepid.Gameplay.Entities.Player.Sentinel.StateMachine.States
{
    public class SentinelStateDashRecovery : SentinelState
    {
        [GroupConfigurations, SerializeField] private AnimationClip dashRecovery;

        private Timer Timer { get; } = new();
        
        public override SentinelStateType GetStateKey()
        {
            return SentinelStateType.DashRecovery;
        }

        protected override void Subscriptions()
        {
        }

        protected override void RunOnEnter(ParameterStore parameterStore)
        {
            Brain.Entity.ModelAnimation.CrossFade(dashRecovery, 0.05f);
            if (Brain.Controls.OnCadence)
            {
                TimeSimulation.Instance.AsBreathMotion();
            }
        }

        protected override void RunOnExit()
        {
            Timer.Stop();
            TimeSimulation.Instance.AsNormalMotion();
        }
        
        public override void RunOnFirstFrameOnly()
        {
            Timer.Start();
        }
        
        public override void RunOnUpdate()
        {
            if (Timer.IsNotRunning)
            {
                if (TryConsumeDash())
                {
                    Brain.ChangeState(SentinelStateType.DashImpulse);
                    var movement = Brain.InputResolver.Sentinel.Movement();
                    var forward = Brain.Entity.Forward;
                    var direction = GonFunctions
                        .ConstrainDirectionToForwardCone(movement, forward, Brain.Config.DashRecovery.DashMaxAngleFromForward);
                    Brain.Entity.ChangeOrientation(direction);
                    return;
                }
                if (Brain.Entity.IsGrounded)
                {
                    Brain.ChangeState(Brain.Controls.ShouldDashBreak
                        ? SentinelStateType.DashBreaking
                        : SentinelStateType.DashLanding);
                }
                else
                {
                    Brain.ChangeState(SentinelStateType.Fall);
                }
                return;
            }
            Timer.Update(Time.deltaTime);
            if (Timer.Check(Brain.Config.DashRecovery.Duration))
            {
                Timer.Stop();
                return;
            }

            var speedCurve = Brain.Config.DashRecovery.SpeedCurve;
            var speedFactor = 1f + speedCurve.Evaluate((float)Timer.ElapsedTime / Brain.Config.DashRecovery.Duration);
            Brain.Entity.DesiredVelocity = Brain.Entity.Forward * (Brain.Config.DashRecovery.Speed * speedFactor);
        }
    }
}