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

namespace Rokojori
{ 
  public enum ShaderTransformSpace
  { 
    Local,
    World,
    View
  }

  public enum ShaderStage
  {
    Vertex,
    Fragment
  }

  public static class ShaderTransformSpaceUtility
  {
    public static string Convert( 
      ShaderTransformSpace fromSpace, 
      ShaderTransformSpace toSpace, 
      bool isDirection, 
      ShaderStage shaderStage, 
      string varName 
    )
    {
      if ( ShaderTransformSpace.Local == fromSpace )
      {
        return ConvertFromLocal( toSpace, isDirection, shaderStage, varName );
      }

      if ( ShaderTransformSpace.World == fromSpace )
      {
        return ConvertFromWorld( toSpace, isDirection, varName );
      }

      if ( ShaderTransformSpace.View == fromSpace )
      {
        return ConvertFromView( toSpace, isDirection, shaderStage, varName );
      }

      return null;
    }

    public static string FromViewPoint( ShaderTransformSpace toSpace, string varName = "VERTEX" )
    {
      return ConvertFromView( toSpace, false, ShaderStage.Fragment, varName );
    }

    public static string FromPoint( ShaderTransformSpace fromSpace, ShaderTransformSpace toSpace, string varName = "VERTEX" )
    {
      return Convert( fromSpace, toSpace, false, ShaderStage.Fragment, varName );
    }

    public static string FromViewDirection( ShaderTransformSpace toSpace, string varName = "VERTEX" )
    {
      return ConvertFromView( toSpace, false, ShaderStage.Fragment, varName );
    }

    public static string ConvertFromLocal( ShaderTransformSpace toSpace, bool isDirection, 
      ShaderStage shaderStage, string varName  )
    {
      if ( ShaderTransformSpace.Local == toSpace )
      {
        return varName;
      }

      var target = ShaderTransformSpace.World == toSpace ? "World" : "View";
      var matrix = ShaderTransformSpace.World == toSpace ? "MODEL_MATRIX" : "MODELVIEW_MATRIX"; 

      if ( ShaderStage.Fragment == shaderStage )
      {
        matrix = ShaderTransformSpace.World == toSpace ? "MODEL_MATRIX" : "VIEW_MATRIX * MODEL_MATRIX"; 
      }

      var direction = isDirection ? "Direction" : "";

      
      return $"localTo{target}{direction}( {varName}, {matrix} )";
    }

    public static string ConvertFromWorld( ShaderTransformSpace toSpace, bool isDirection, string varName  )
    {
      if ( ShaderTransformSpace.World == toSpace )
      {
        return varName;
      }

      var target = ShaderTransformSpace.Local == toSpace ? "Local" : "View";
      var matrix = ShaderTransformSpace.Local == toSpace ? "MODEL_MATRIX" : "VIEW_MATRIX"; 
      var direction = isDirection ? "Direction" : "";

      
      return $"worldTo{target}{direction}( {varName}, {matrix} )";
    }

    

    public static string ConvertFromView( ShaderTransformSpace toSpace, bool isDirection,  
      ShaderStage shaderStage, string varName  )
    {
      if ( ShaderTransformSpace.View == toSpace )
      {
        return varName;
      } 

      var target = ShaderTransformSpace.Local == toSpace ? "Local" : "World";
      var matrix = ShaderTransformSpace.Local == toSpace ? "MODELVIEW_MATRIX " : "INV_VIEW_MATRIX"; 

       if ( ShaderStage.Fragment == shaderStage )
      {
        matrix = ShaderTransformSpace.Local == toSpace ? "INV_VIEW_MATRIX, MODEL_MATRIX" : "INV_VIEW_MATRIX"; 
      }

      var direction = isDirection ? "Direction" : "";

      
      return $"viewTo{target}{direction}( {varName}, {matrix} )";
    }
  }
}