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

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

    [Export]
    public float splineRadius = 0.5f;

    [Export]
    public float resolutionU = 0.1f;
    
    [Export]
    public int maxSegmentsU = 64;  

    
    [Export]
    public float resolutionV = 0.5f;

    [Export]
    public int maxSegmentsV = 1024;  

    [Export]
    public MeshInstance3D output;

    [Export]
    public bool undistortSplineSegments = false;

    protected override void _OnTrigger()
    {
      CreateMesh();
    }

    public void CreateMesh()
    {
      var curve = spline.GetCurve();
      
      var length = curve.ComputeLength( 100 );
      var numPoints = Mathf.Clamp( length / resolutionU, 2, maxSegmentsU );

      var uSegments = (int) ( Mathf.Clamp( splineRadius * 2f * 3.14f / resolutionV, 3, maxSegmentsV ) );
      var vSegments = (int) ( numPoints - 1 );
      

      var uvFunction =  ( Vector2 uv ) =>
        {          
          var t = undistortSplineSegments ? curve.ComputeTforNormalizedCurveLength( uv.Y, vSegments ) : uv.Y;
          var index = curve.NormalizedToPointIndex( t );
          var pose = curve.PoseAt( t );        
          var radiusSize = splineRadius;

          var angle = uv.X * 2f * Mathf.Pi;
          var circlePose = Pose.Create( Vector3.Zero, pose.rotation * Math3D.RotateZ( angle ) );      

          circlePose.rotation = circlePose.rotation.Normalized();
          var circleStart = Vector3.Up * radiusSize;         
          var positionOnCircle = circlePose.Apply( circleStart );

          return Pose.Create( positionOnCircle + pose.position, circlePose.rotation );
        };

      var mg = MeshGeometry.CreateFromUVFunction( uvFunction, uSegments, vSegments );
      mg.Add( MeshGeometry.CreateCapUVFunction( uvFunction, uSegments, true ) ); 
      mg.Add( MeshGeometry.CreateCapUVFunction( uvFunction, uSegments, false ) ); 

      if ( output == null )
      {
        output = this.CreateChild<MeshInstance3D>( "Spline MeshInstance");
      }

      output.Mesh = mg.GenerateMesh();


    }
  }
}