using Godot;
using System.Collections;
using System.Collections.Generic;
using Godot.Collections;

namespace Rokojori
{
  [Tool]
  [GlobalClass, Icon("res://addons/rokojori_action_library/Icons/CCJump.svg")]
  public partial class Jump:CharacterControllerAction
  {
    [Export]
    public Sensor button;

    [Export]
    public Action onJump;

    [ExportGroup( "Jumping")]    
    
    [Export]
    public JumpStrength strength;
    [Export]
    public float minJumpDuration = 0.5f;

    [Export]
    public Gravity gravity;



    [ExportGroup( "Movement")]    

    [Export]
    public float forwardStrength = 0;

    [Export]
    public float rightStrength = 0;

    [Export]
    public CharacterMovement movement;    

    [Export( PropertyHint.Range, "0,5" )]
    public float movementToJumpDirection = 0.5f;

    [Export( PropertyHint.Range, "0,100" )]
    public float movementDirectionToFixedJumpDirection = 0.5f;
    
    [Export]
    public float movementTresholdForJumpDirection = 1f;


    [ExportGroup( "Air Control")]

    [Export]
    public GravityStrength airControlGravityStrength;

   [Export]
    public float maxAirControlDuration;

    [Export]
    public Curve airControlCurveStrength = MathX.Curve( 1, 0 );


    
    float jumpedDuration;

    bool canJump = false;

    bool jumpPressing = false;

    bool needsToRelease = false;

    bool jumping = false;
    float jumpStart = 0;

    Vector3 jumpDirection;

    public override bool HasActiveForces()
    {
      return jumping;
    }

    public bool IsJumping()
    {
      return jumping;
    }

    public float GetJumpStartTime()
    {
      return jumpStart == -1 ? 0 : ( TimeLine.osTime - jumpStart );
    }

    protected override void _OnTrigger()
    { 
      if ( ! jumping && isGrounded && button.isDown )
      {
        _StartJump();
      }

      if ( jumping )
      {
        _OnJumping();
      } 

    }

    protected void _StartJump()
    {
      // jumpPressing = true;
      jumpedDuration = 0;
      jumping = true;
      jumpStart = TimeLine.osTime;

      Trigger( onJump );
      
      jumpDirection = Vector3.Up * strength.GetJumpStrength( this );

      if ( movement != null )
      {
        var currentMovement = movement.smoothedMovement * controller.delta;
        this.LogInfo( body.Velocity, currentMovement );

        if ( currentMovement.Length() > movementTresholdForJumpDirection )
        {
          var xz = currentMovement;
          xz.Y = 0;          

          jumpDirection += xz * movementToJumpDirection + xz.Normalized() * movementDirectionToFixedJumpDirection;
        }

      }

      jumpDirection += body.GlobalForward() * forwardStrength;
      jumpDirection += body.GlobalRight() * rightStrength;

      SetVelocity( jumpDirection, 1 );
      this.LogInfo( jumpDirection );

      
    }

    protected void _OnJumping()
    {
      if ( jumping && jumpedDuration < minJumpDuration )
      {
        if ( controller.grounding != null )
        { 
          controller.grounding.ApplyUngroundedOverwrite();
        } 
        
      }

      if ( airControlGravityStrength != null && gravity != null && button.isHold  && 
        jumpedDuration < maxAirControlDuration && body.Velocity.Y > 0
      )
      {
        var gravityStrength = airControlGravityStrength.GetGravityStrength( gravity );
        var gravityStrengthMultiply = 1f;

        if ( airControlCurveStrength != null )
        {
          gravityStrengthMultiply = airControlCurveStrength.Sample( jumpedDuration / maxAirControlDuration );
        }
        
        AddVelocity( gravityStrength * Vector3.Up * gravityStrengthMultiply );
      }

      jumpedDuration += controller.delta;

      if ( jumpedDuration > minJumpDuration )
      {
        jumping = false;
      }
    }

    
  }
}