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



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

    [Export]
    public Texture2D target;

    [Export]
    public MeshInstance3D meshInstance3D;


    [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();

      this.LogInfo( "Creating context" );
      var ctx = RDContext.Local();
      ctx.messageLogLevel = Messages.GetLevel( MessageType.Verbose );

      this.LogInfo( "Creating program" );
      ctx.SetProgramFromPath( CEG_AlphaColorDilation.shaderPath );

      this.LogInfo( "Creating textures" );
      
      var outputTexture = RDTexture.Create( ctx, viewport.Size, viewPortFormat );
      this.LogInfo( "Usage", RDTextureFormats.UsageInfo( outputTexture.format.UsageBits ) );
      outputTexture.SetData( new Color( 1, 1, 1, 1 ) );

      

      // var inputTexture  = RDTexture.CreateCopyFrom( ctx, viewport );
      var inputTexture = RDTexture.Create( ctx, viewport.Size, viewPortFormat );
      inputTexture.SetData( viewPortData );
      // inputTexture.SetData( new Color( 0, 1, 0, 1 ) );

      this.LogInfo( "Assigning input texture:", ctx.shader, ctx.shader.rid );
      ctx.AssignTexture( inputTexture );

      this.LogInfo( "Assigning output texture" ); 
      ctx.AssignTexture( outputTexture );

      this.LogInfo( "Compute group sizes" );
      ctx.CalculateComputeGroups( 8, viewport.Size );

      this.LogInfo( "Process compute program" );
      ctx.ProcessComputeProgram();

      this.LogInfo( "Waiting to render" );
     
      ctx.SubmitAndSync();

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

      var data = outputTexture.GetData();
      data = data.ToList().ToArray();

      this.LogInfo( "Copying texture" );
      
      ctx.SubmitAndSync();



      await this.RequestNextFrame();

      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();


      

    
    }

  
  } 
}