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

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

    [Export]
    public Node3D pivotPose;

    [Export]
    public float tubePosition;

    [Export]
    public float scale = 1f;
    
    [Export]
    public float widthScale = 1f;

    [Export]
    public float heightScale = 1f;

    [Export]
    public ShapeOrientationMode shapeOrientationMode = ShapeOrientationMode.Auto;

    bool cached = false;

    bool shapeForward = true;
    SplineCurve radialShape;
    

    public void ClearCache()
    {
      cached = false;
    }

    public Pose GetPose( bool undistort, int splineSegments, int radialSegments, Pose pose, Vector2 uv, Vector3 scale, Quaternion twistRotation )
    {
      if ( ! cached )
      {
        radialShape = spline.GetCurve();
        shapeForward = true;
        
        if ( pivotPose != null )
        {
          radialShape = radialShape.ApplyPose( Pose.InverseFrom( pivotPose ) );
        }

        radialShape = radialShape.CloneForXY();        

        if  ( ShapeOrientationMode.Original != shapeOrientationMode )
        {
          if ( ShapeOrientationMode.Auto == shapeOrientationMode )
          {
            var path = radialShape.SampleXYPath( radialSegments );
            shapeForward = path.isClockwise;
          }

          if ( ShapeOrientationMode.Reverse == shapeOrientationMode )
          {
            shapeForward = false;
          }
          
        }

        cached = true;
      }
      

      scale.X *= widthScale * this.scale;
      scale.Y *= heightScale * this.scale;

      var radialT = ! shapeForward ? uv.X : ( 1f - uv.X );
      radialT = undistort ? 
                  radialShape.UtoT( radialT, splineSegments ) : 
                  radialT;  

      var shapePosition = radialShape.PositionAt( radialT ) * scale;
      var shapeTangent  = radialShape.TangentAt( radialT, 1f / radialSegments ) * scale; 


      shapePosition = twistRotation * shapePosition;
      shapeTangent  = twistRotation * shapeTangent;

      var angle = Math3D.AngleXY( shapeTangent ) + Mathf.Pi;
      var rotation = Math3D.RotateZ( angle );
        
      var combinedRotation = pose.rotation * rotation;

      var rotatedShapePosition = Vector3.Zero;

      rotatedShapePosition = pose.rotation * shapePosition;            

      return Pose.Create( rotatedShapePosition + pose.position, combinedRotation );
    }
  }

}