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

namespace Rokojori
{
  [Tool]
  [GlobalClass, Icon("res://addons/rokojori_action_library/Icons/CharacterController.svg")]
  public partial class CharacterController:Node
  {
    [Export]
    public CharacterBody3D body;

    public enum CharacterUpdateMode
    { 
      Process,
      Physics_Process
    }

    [Export]
    public CharacterUpdateMode characterUpdateMode = CharacterUpdateMode.Process;

    [Export]
    public Node actionsContainer;

    [Export]
    public Node3D graphics;
    
    [Export]
    public Smoothing rotationSmoothing;

    [Export]
    public Smoothing positionSmoothing;

    [Export]
    public Node3D groundedTransform;

    [Export]
    public float lastGroundedHeight = 0;


    public float delta = 0;   

  
    public override void _Process( double delta )
    {
      if ( Engine.IsEditorHint() && graphics == null || body == null )
      {
        return;
      }

      if ( CharacterUpdateMode.Process == characterUpdateMode )
      {
        ProcessActions( (float) delta );
      }
      
      if ( body.IsOnFloor() )
      {
        lastGroundedHeight = graphics.GlobalPosition.Y; 
      }

    
      AssignGroundedTransform();    
      

      // Pose.CopyTo( body, graphics );
    } 

    void SmoothPose( float delta )
    {
      var smoothingDelta = delta;
      graphics.GlobalPosition = Smoothing.Apply( positionSmoothing, body.GlobalPosition, smoothingDelta );
      graphics.SetGlobalQuaternion( Smoothing.Apply( rotationSmoothing, body.GlobalQuaternion(), smoothingDelta ) );

    }

    void AssignGroundedTransform()
    {
      if ( groundedTransform == null )
      {
        return;
      }


      var groundedPosition = graphics.GlobalPosition;
      groundedPosition.Y = lastGroundedHeight;

      groundedTransform.GlobalPosition = groundedPosition;
      groundedTransform.SetGlobalQuaternion( graphics.GlobalQuaternion() );
    }

    // #if !TOOLS 
    public override void _PhysicsProcess( double delta )
    {
      if ( Engine.IsEditorHint() || graphics == null || body == null )
      {
        return;
      }

      if ( CharacterUpdateMode.Physics_Process == characterUpdateMode )
      {
        ProcessActions( (float) delta );
      }
    }
    // #endif

    void ProcessActions( float delta )
    {
      this.delta = (float) delta;
      var container = actionsContainer == null ? this : actionsContainer;
      Nodes.ForEachDirectChild<CharacterControllerAction>(
        container,
        ( c ) =>
        { 
          if ( 
            ! c.enabled || 
            c.condition != null && ! c.condition.Evaluate() || 
            c.sceneCondition != null && ! c.sceneCondition.Evaluate() 
          )
          {
            return;
          }

          c.SetCharacterController( this );

          Action.Trigger( c );
        }
      );

      SmoothPose( delta );
    }
  }
}