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



namespace Rokojori
{
  [Tool]
  [GlobalClass]
  public partial class GrabTexture2:Action
  { 
    [Export]
    public SubViewport viewport;

    [Export]
    public Texture2D target;

    [Export]
    public MeshInstance3D meshInstance3D;

    [Export( PropertyHint.Range, "0,1" ) ]
    public float intensity;

    [Export( PropertyHint.Range, "0,100" ) ]
    public float noise;

    [Export( PropertyHint.Range, "1,100" ) ]
    public float kernelOffset;

    [Export( PropertyHint.Range, "1,50" ) ]
    public float kernelRadius;


    


    [ExportToolButton( "Grab Texture")]
    public Callable GrabButton => Callable.From( 
      () => 
      {
        Grab();
      } 
    );

    async void Grab()
    {   
      var updateMode = viewport.RenderTargetUpdateMode;

      if ( updateMode != SubViewport.UpdateMode.Always )
      {
        viewport.RenderTargetUpdateMode = SubViewport.UpdateMode.Always;
        await this.RequestNextFrame();
        viewport.RenderTargetUpdateMode = updateMode;
      }

      var viewPortFormat = RDTextureFormats.GetDataFormat( viewport );
      var viewPortData = viewport.GetTexture().GetImage().GetData();
      var viewPortSize = viewport.Size;

      this.LogInfo( "Creating context" );
      var ctx = RDContext.Local();
      ctx.computeSize = viewPortSize;
      ctx.messageLogLevel = Messages.GetLevel( MessageType.Verbose );
      
      
      this.LogInfo( "Creating textures" );
      
      var outputTexture = RDTexture.Create( ctx, viewport.Size, viewPortFormat );
      this.LogInfo( "Usage", RDTextureFormats.UsageInfo( outputTexture.format.UsageBits ) );
     

      var inputTexture = RDTexture.Create( ctx, viewport.Size, viewPortFormat );
      inputTexture.SetData( viewPortData );

      this.LogInfo( "Creating graph" );

      var graph = CreateGraph( ctx, inputTexture, outputTexture );

      this.LogInfo( "Process graph" );
      graph.ProcessForView();
     
      ctx.SubmitAndSync();

      var width = inputTexture.width;
      var height = inputTexture.height;
      var format = inputTexture.imageFormat; 

      var data = inputTexture.GetData();

      ctx.SubmitAndSync();
      await this.RequestNextFrame();


      this.LogInfo( "Copying texture" );

      var image = Image.CreateFromData( width, height, false, format, data );
      var buffer = TextureCombinerBuffer.From( ImageTexture.CreateFromImage( image ) );

      target = buffer.CreateImageTexture();

      var material3D = (StandardMaterial3D) meshInstance3D.MaterialOverride;
      material3D.AlbedoTexture = target;

      ctx.CleanUp();

      await this.RequestNextFrame();

    
    }

    RDGraph CreateGraph( RDContext ctx, RDTexture it, RDTexture ot )
    {
      var graph = new RDGraph( ctx );

      var viewTexture = RG_BufferTexture.From( graph, it );
      var bufferTexture = RG_BufferTexture.From( graph, ot );    

      var copy = new CEG_Copy( graph );
      var blur = new RG_BoxBlur( graph );

      graph.InitializeNodes();

      copy.SetTextureSlotInputs( viewTexture, bufferTexture );
      blur.SetTextureSlotInputs( copy.output, copy.input ); 


      graph.SetProcessOrder( 
        viewTexture, bufferTexture, 
        copy, blur 
      );

      blur.constants.Set(
        intensity,
        noise, 
        kernelOffset, 
        kernelRadius
      );

      ctx.Verbose( "Radial Blur constants:", blur.constants.size );
      return graph;
    }

  
  } 
}