
using Godot;
using System.Collections.Generic;

namespace Rokojori
{  
  public class RDShaderProcessor:RGGraphProcessor
  {
    protected string _shaderPath;

    public RDShaderProcessor( RDGraph graph, string shaderPath ):base( graph )
    {
      this._shaderPath = shaderPath;
    }

    protected RDShader _shader;
    protected RDPipeline _pipeline;
    protected RDPushConstants _constants = new RDPushConstants();
    public RDPushConstants constants => _constants;
    protected Vector3I _groupSize = new Vector3I( 8, 8, 0 );
    protected List<CompositorEffectGraphTextureSlot> _textureSlots = new List<CompositorEffectGraphTextureSlot>(); 
    
    protected override void OnInitialize()
    {
      graph.context.Verbose( GetType().Name, "Trying to load shader: ", _shaderPath );

      if ( _shaderPath == null )
      {
        graph.context.Error( GetType().Name, "_shaderPath == null" );
        return;
      }

      var glslFile = GD.Load<RDShaderFile>( _shaderPath );

      if ( glslFile == null )
      {
        graph.context.Error( GetType().Name, "Couldn't load shader at path:", _shaderPath );
        return;
      }

      _shader = RDShader.CreateFromSpirV( graph.context, glslFile.GetSpirV() );      

      if ( _shader == null )
      {
        graph.context.Error( GetType().Name, "Couldn't create shader from code, path:", _shaderPath );
        return;
      }

      _pipeline = RDPipeline.CreateCompute( graph.context, _shader );

      if ( _shader == null )
      {
        graph.context.Error( GetType().Name, "Couldn't create pipeline from compiled shader, path:", _shaderPath );
        return;
      }
      
      graph.context.Verbose( GetType().Name, "Created shader at path: ", _shaderPath );
    } 

    public bool debugging = false;
   
    public override void Process()
    {
      var context = graph.context;

      context.Clear();
      context.CalculateSceneComputeGroups( _groupSize );
      context.SetShaderAndPipeline( _shader, _pipeline );

      context.Verbose( GetType().Name, "Setting texture uniforms", _textureSlots.Count );

      int index = 0;

      // if ( debugging )
      // {
      //   RJLog.Log( this.GetType().Name, "Num Texture Slots:", _textureSlots.Count );
      // }

      _textureSlots.ForEach( t => 
        { 
          index++;

        

          t.ResolveTexture();
          var texture = t.GetTexture();

          if ( texture == null || ! texture.rid.IsValid )
          {
            if ( texture == null )
            {
              context.Error( index, "Texture is null" );
            }
            else
            {
              context.Error( index, "Texture is not valid:", texture.rid  );
            }
            
            graph.context.AssignMissingTexture( t.sampler );
            return;
          }

          graph.context.AssignTexture( texture, t.sampler ); 


          
        } 
      );      
    

      if ( _constants.size > 0 )
      {        
        context.Verbose( GetType().Name, "Setting constants", _constants.size );
        context.pushConstants = _constants;
      }  
      else
      {
        context.Verbose( GetType().Name, "No constants" );
      }    

      context.Verbose( GetType().Name, "Process Compute Program", _constants.size );
      context.ProcessComputeProgram();
    }
  }
}