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 );
      }

      // positionSmoother.CopyPosition( graphics, body, rotationSmoothingDuration, delta );
      // rotationSmoother.CopyRotation( graphics, body, positionSmoothingDuration, delta );    

      graphics.GlobalPosition = Smoothing.Apply( positionSmoothing, body.GlobalPosition, this.delta );
      graphics.SetGlobalQuaternion( Smoothing.Apply( rotationSmoothing, body.GetGlobalQuaternion(), this.delta ) );

      if ( body.IsOnFloor() )
      {
        lastGroundedHeight = graphics.GlobalPosition.Y; 
      }

      var grounedPosition = graphics.GlobalPosition;
      grounedPosition.Y = lastGroundedHeight;
      groundedTransform.GlobalPosition = grounedPosition;
      groundedTransform.SetGlobalQuaternion( graphics.GetGlobalQuaternion() );

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

    public override void _PhysicsProcess( double delta )
    {
      if ( CharacterUpdateMode.Physics_Process == characterUpdateMode )
      {
        ProcessActions( (float) delta );
      }
    }
    
    void ProcessActions( float delta )
    {
      this.delta = (float) delta;
      var container = actionsContainer == null ? this : actionsContainer;
      Nodes.ForEachDirectChild<CharacterControllerAction>( container, Action.Trigger );
    }
  }
}