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

namespace Rokojori
{ 
  
  public class Shaders
  {  
    public static List<UniformMember> GetUniformMembersOfStandardMaterial()
    {
      var list = new List<UniformMember>();

      var m = new StandardMaterial3D();

      list.AddRange( 
        Lists.Map( 
          ReflectionHelper.GetDataMemberInfos<Color>( m ), 
          c => UniformMember.Create( c.Name, Variant.Type.Color )
        )      
      );

      list.AddRange( 
        Lists.Map( 
          ReflectionHelper.GetDataMemberInfos<float>( m ), 
          c => UniformMember.Create( c.Name, Variant.Type.Float )
        )      
      );   

      list.AddRange( 
        Lists.Map( 
          ReflectionHelper.GetDataMemberInfos<bool>( m ), 
          c => UniformMember.Create( c.Name, Variant.Type.Bool )
        )      
      );

      list.AddRange( 
        Lists.Map( 
          ReflectionHelper.GetDataMemberInfos<Vector2>( m ), 
          c => UniformMember.Create( c.Name, Variant.Type.Vector2 )
        )      
      );   

      list.AddRange( 
        Lists.Map( 
          ReflectionHelper.GetDataMemberInfos<Vector3>( m ), 
          c => UniformMember.Create( c.Name, Variant.Type.Vector3 )
        )      
      );   

      list.AddRange( 
        Lists.Map( 
          ReflectionHelper.GetDataMemberInfos<Vector4>( m ), 
          c => UniformMember.Create( c.Name, Variant.Type.Vector4 )
        )      
      );  

      list.AddRange( 
        Lists.Map( 
          ReflectionHelper.GetDataMemberInfos<Color>( m ), 
          c => UniformMember.Create( c.Name, Variant.Type.Color )
        )      
      );  

      return list;
    }

    public static UniformMember GetUniformMemberByName( Material material, string name )
    {
      var members = GetUniformMembers( material );

      return members.Find( m => m.name == name );
    }

    public static List<UniformMember> GetUniformMembers( Material material )
    {
      if ( material is StandardMaterial3D )
      {
        return GetUniformMembersOfStandardMaterial();
      }

      var shaderMaterial = material as ShaderMaterial;
      return GetUniformMembers( shaderMaterial.Shader );
    }


    public static List<UniformMember> GetUniformMembers( Shader shader )
    {
      var list = new List<UniformMember>();
      
      var uniforms = shader.GetShaderUniformList();

      foreach ( var u in uniforms )
      {
        var d = u.AsGodotDictionary();


        var member = new UniformMember();

        member.name = d[ "name" ].AsString();

        member.type = (Variant.Type) d[ "type" ].AsInt32();
        
        member.hint = (PropertyHint) d[ "hint" ].AsInt32();
        member.hintString = d[ "hint_string" ].AsString();
        member.usage = d[ "usage" ].AsInt32();


        list.Add( member );
      }      

      return list;
    }

    public static List<string> GetUniformNames( Shader shader )
    {
      var list = new List<string>();
      
      var uniforms = shader.GetShaderUniformList();

      foreach ( var p in uniforms )
      {
        var d = p.AsGodotDictionary();
        var name = d[ "name" ].ToString();

        list.Add( name );
      }      

      return list;
    }
  }
}