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

namespace Rokojori
{ 
  [Tool]
  [GlobalClass]
  public partial class AxisMask:SpatialMask
  { 
    public enum Source
    {
      Vertex,
      Uniform
    } 
      
    [Export]
    public Source fromSource = Source.Vertex;

    [Export]
    public ShaderTransformSpace uniformSourceFromSpace;

    [Export]
    public ShaderTransformSpace toSpace;

    [Export]
    public Math3D.Axis toAxis;

    [Export]
    public bool eulerRotation = true; 

    [Export]
    public bool clamp = true;
    
    
    public override List<ShaderCode> GetMaskCode( ShaderGenerationContext context, string contextName, string maskName )
    {
      if ( ShaderPhase.Includes == context.phase )
      {
        return IncludeTransformLibrary().Concat( IncludeMathLibrary() );
      }

      var ownName = contextName + "AxisMask";
      var nameMin = ownName + "_Min";
      var nameMax = ownName + "_Max";
      var uniformPosition = ownName + "_AxisPosition";
      var uniformRotation = ownName + "_AxisRotation";

      var uniformGroup = contextName + "AxisMask";


      if ( ShaderPhase.Variables == context.phase )
      { 
        var code = new List<ShaderCode>();
        code.AddRange( ToCode( Uniform( nameMin, 0 ) + "\n" ) );
        code.AddRange( ToCode( Uniform( nameMax, 0 ) + "\n" ) );

        if ( Source.Uniform == fromSource )
        { 
          code.AddRange( ToCode( Uniform( uniformPosition, Vector3.Zero ) ) );
        }

        if ( eulerRotation )
        { 
          code.AddRange( ToCode( Uniform( uniformRotation, Vector3.Zero ) ) );
        }

        

        return AsUniformGroup( uniformGroup, code ); 
      }

      if ( context.isFragmentPhase )
      {
        var variableName = Source.Vertex == fromSource ? "VERTEX" : uniformPosition;

        if ( eulerRotation )
        {
          variableName = $"rotateEulerDegrees( {variableName}, {uniformRotation} )";
        }

        var fromSpace = Source.Vertex == fromSource ? ShaderTransformSpace.View : uniformSourceFromSpace;
        var position = ShaderTransformSpaceUtility.FromPoint( fromSpace, toSpace, variableName );
        var member = $"({position})." + ( toAxis + "" ).ToLower();
        
        var func = "normalizeToRange01";

        if ( ! clamp )
        {
          func = "normalizeToRange";
        }      

        var code = 
        @$"
        
        {{

          float {contextName}_AxisValue = {member}; 
          float {contextName}_normalizedValue = {func}( {contextName}_AxisValue, {nameMin}, {nameMax } );

          {maskName} = {contextName}_normalizedValue;
        }}        
        ";
        return ToCode( code.Indent( "    " ) + "\n" );
      }

      return null;
    }
   
  }
}