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

namespace Rokojori
{
  [Tool]
  [GlobalClass]
  public partial class TurnMovementType:CharacterMovementType
  {
    [Export]
    public CharacterDirectionProcessing directionProcessing;    

    [ExportGroup( "Movement" )]
    [Export]
    public Sensor up;

    [Export]
    public Sensor down;

    [Export]
    public Sensor left;

    [Export]
    public Sensor right;    

    [ExportGroup( "Strafing" )]
    [Export]
    public bool useBodyDirection = true;

    [Export]
    public Sensor strafeBack;

    [Export]
    public Sensor strafeLeft;

    [Export]
    public Sensor strafeRight;    

    [Export]
    public float strafeBackSpeedMultiply = 1.0f;

    [Export]
    public float strafeSidewardsSpeedMultiply = 1.0f;

    [ExportGroup( "Tweaking" )]
    [Export]
    public float yDeltaOffset = 0.01f;

    public override void ProcessMovement( CharacterMovementData characterMovementData )
    {
      var characterMovement = characterMovementData.characterMovement;
      var directionSource = characterMovement.directionSource;
      var body = characterMovement.body;

      var dir = directionSource != null ? directionSource : body;
      var forwardDirection = dir.GlobalForward();
      var rightDirection   = dir.GlobalRight();
      var forwardStrafe = useBodyDirection ? body.GlobalForward() : dir.GlobalForward();
      var rightStrafe  = useBodyDirection ? body.GlobalRight() : dir.GlobalRight();

      if ( CharacterDirectionProcessing.Zero_Y_And_Normalize == directionProcessing ) 
      {
        forwardDirection.Y = 0;
        rightDirection.Y = 0;        
      } 
      else if ( CharacterDirectionProcessing.Project_On_TransformPlane == directionProcessing ) 
      {
        var bodyPlane    = Plane3.CreateFromNode3D( body );
        forwardDirection = bodyPlane.ConstrainToPlane( forwardDirection + body.GlobalPosition ) - body.GlobalPosition;
        rightDirection   = bodyPlane.ConstrainToPlane( rightDirection + body.GlobalPosition ) - body.GlobalPosition;
      }

      forwardDirection.Y += yDeltaOffset;
      rightDirection.Y += yDeltaOffset;

      forwardDirection = forwardDirection.Normalized();
      rightDirection   = rightDirection.Normalized();


      var direction = Sensors.FourDirectional( left, right, up, down );

      // this.LogInfo( "moving:", "fw", forwardDirection, "r", rightDirection, "dir:", direction );

      var movement = forwardDirection * - direction.Y  * characterMovement.moveSpeed;

      movement += rightDirection * direction.X * characterMovement.moveSpeed; 

      var turningForwardDirection = movement.Normalized();

      if ( Sensors.IsActive( strafeBack ) )
      {
        movement += -Sensors.GetValue( strafeBack ) * forwardStrafe * characterMovement.moveSpeed * strafeBackSpeedMultiply;
        turningForwardDirection = forwardDirection;
      }

      if ( Sensors.IsActive( strafeLeft ) || Sensors.IsActive( strafeRight ) )
      {
        var strafeStrength = Sensors.PolarAxis( strafeLeft, strafeRight );
        movement += strafeStrength * rightStrafe * characterMovement.moveSpeed * strafeSidewardsSpeedMultiply;
        turningForwardDirection = forwardDirection;
      }

      movement = movement.ConstrainLength( characterMovement.moveSpeed );

      characterMovementData.movement = movement;
      characterMovementData.isMovingForward = ! Math3D.FacingSameDirection( turningForwardDirection, forwardDirection );
      characterMovementData.forwardDirection = turningForwardDirection;


    }
  }
}