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

namespace Rokojori
{  

  public enum SVGPathInstructionType
  {
    MoveTo,
    LineTo,
    QuadraticBezierTo,
    CubicBezierTo,
    ArcTo,
    Close    
  }

  public class SVGPathInstruction
  {
    public SVGPathCommand sourceCommand;
    public int sourceCommandIndex;
    public SVGPathInstructionType type = SVGPathInstructionType.MoveTo;
    public Vector2 startPoint = Vector2.Zero;
    public Vector2 controlPoint1 = Vector2.Zero;
    public Vector2 controlPoint2 = Vector2.Zero;
    public Vector2 endPoint = Vector2.Zero;
    public Vector2 radius = Vector2.Zero;
    public float angle = 0;
    public bool largeArcFlag = false;
    public bool sweepFlag = false;

    public override string ToString()
    {
      return GetInfo();
    }

    public void AddPoints( List<Vector2> pathPoints, float resolution = 1, int maxPoints = 1000 )
    {
      if ( SVGPathInstructionType.MoveTo == type )
      {
        pathPoints.Add( startPoint );
      }
      else if ( 
        SVGPathInstructionType.LineTo == type ||
        SVGPathInstructionType.Close == type
      )
      {
        pathPoints.Add( endPoint );
      }
      else if ( SVGPathInstructionType.ArcTo == type )
      {
        var centerPosition = new Vector2();
        var centerRadius   = new Vector2();
        var centerAngles   = new Vector2();
        

        SVGArc.EndpointToCenterArc(
          startPoint, endPoint, radius, angle, largeArcFlag, sweepFlag,
          out centerPosition, out centerRadius, out centerAngles ); 


        var arcResolution = Math.Max( centerRadius.X, centerRadius.Y ) / resolution;

        arcResolution = Mathf.Clamp( arcResolution, 1, maxPoints ); 
        
        RJLog.Log( "Arc Resolution", arcResolution );


        for ( int i = 1; i < arcResolution - 1; i++ )
        {
          var t = centerAngles.Y * ( (float)i / ( arcResolution - 1 ) );
          var arcPoint = SVGArc.GetPointOnCenterArc( centerRadius, centerAngles.X, t ) + centerPosition;

          pathPoints.Add( arcPoint );
        }

        pathPoints.Add( endPoint );

      }
      else if ( 
        SVGPathInstructionType.QuadraticBezierTo == type || 
        SVGPathInstructionType.CubicBezierTo == type
       )
      {
        var isQuadratic = SVGPathInstructionType.QuadraticBezierTo == type;

        var curve = isQuadratic ?
          new CustomCurve2( t => QuadraticBezier.Compute( t, startPoint, controlPoint1, endPoint ) ) :
          new CustomCurve2( t => CubicBezier.Compute( t, startPoint, controlPoint1, controlPoint2, endPoint ) )
        ;

        var length = curve.ComputeLength( isQuadratic ? 4 : 6 );

        var numPoints = Mathf.Clamp( Mathf.RoundToInt( length / resolution ), 1, maxPoints ); 

        for ( int i = 1; i < numPoints - 1; i++ )
        {
          var t = (float) i / ( numPoints - 1 );
          pathPoints.Add( curve.SampleAt( t ) );
        }

        pathPoints.Add( curve.SampleAt( 1 ) );
      }
    }

    public string GetInfo()
    {
      var infos = new List<object>();
      infos.Add( type );

      if ( SVGPathInstructionType.MoveTo == type )
      {
        infos.Add( endPoint );
      }
      else if ( SVGPathInstructionType.LineTo == type )
      {
        infos.Add( startPoint );
        infos.Add( endPoint );
      }
      else if ( SVGPathInstructionType.QuadraticBezierTo == type )
      {
        infos.Add( startPoint );
        infos.Add( controlPoint1 );
        infos.Add( endPoint );
      }
      else if ( SVGPathInstructionType.CubicBezierTo == type )
      {
        infos.Add( startPoint );
        infos.Add( controlPoint1 );
        infos.Add( controlPoint2 );
        infos.Add( endPoint );
      }
      else if ( SVGPathInstructionType.ArcTo == type )
      {
        infos.Add( startPoint );
        infos.Add( radius );
        infos.Add( angle );
        infos.Add( largeArcFlag );
        infos.Add( sweepFlag );
        infos.Add( endPoint );
      }

      return RJLog.GetLogString( infos.ToArray() );
    }
  }
}