using System.Collections;
using System.Collections.Generic;
using Godot;
using System;
using System.Threading.Tasks;



namespace Rokojori
{
  [Tool]
  [GlobalClass]
  public partial class ORMBakingPass: _XX_BakingPass
  {
    public ORMBakingPass():base(){}

    protected override void CreateBakingOutputs()
    {
      bakingOutputs = [ BakingOutput.ORM() ];
    }

    protected override bool KeepsOriginalState()
    {
      return false;
    }

    protected override bool KeepsCompositors()
    {
      return true;
    }

    protected override async Task _Bake() 
    {
      Clear( BakingTargetType.ORM );

      SetMaterial();

      await multiBaker.RequestNextFrame();

      var texture = await GrabDilatedTexture( false, false );

      Set( BakingTargetType.ORM, texture );

      return;
    }

    public void SetMaterial()
    {
      Dictionary<Material,Material> materials = new Dictionary<Material, Material>();

      Nodes.ForEach<Node3D>( multiBaker.X_bakingTargetContainer,
        ( n )=>
        {
          SetMaterial( n, materials );
        }
      );
    }


    public static readonly CachedResource<Shader> shader = new CachedResource<Shader>( 
      "res://addons/rokojori_action_library/Runtime/Shading/Shaders/Baking/ChannelCopy.gdshader"
    );  

    void SetChannel( string channel, ShaderMaterial material, Texture2D texture2D, int index )
    {
      material.SetShaderParameter( "channelTexture" + channel, texture2D );
      material.SetShaderParameter( "gamma" + channel, 1.0f );


      var projection = Projection.Zero;

      if ( texture2D != null )
      {
        projection[ index ] = new Vector4( 
          index == 0 ? 1:0, 
          index == 1 ? 1:0, 
          index == 2 ? 1:0, 
          1
        );
      }
    
      

      

      material.SetShaderParameter( "colorMatrix" + channel, projection );
    }

    void SetMaterial( Node3D n, Dictionary<Material,Material> materials )
    {
      var material = Materials.Get<Material>( n );

      if ( material == null )
      {
        // n.LogInfo( "No material found" );
        return;
      }

      if ( ! materials.ContainsKey( material ) )
      {
        var appliedMaterial = new ShaderMaterial();
        appliedMaterial.Shader = shader.Get();
            
        if ( material is StandardMaterial3D sm )
        {
          // n.LogInfo( "StandardMaterial3D found" );

          SetChannel( "A", appliedMaterial, sm.AOTexture, 0 );
          SetChannel( "B", appliedMaterial, sm.RoughnessTexture, 1 );
          SetChannel( "C", appliedMaterial, sm.MetallicTexture, 2 );

          appliedMaterial.SetShaderParameter( "uv1_scale", sm.Uv1Scale );
          appliedMaterial.SetShaderParameter( "uv1_offset", sm.Uv1Offset );

          // appliedMaterial.SetShaderParameter( "use_normalmap", sm.NormalTexture != null );
          // appliedMaterial.SetShaderParameter( "normal_texture", sm.NormalTexture );
          // appliedMaterial.SetShaderParameter( "normal_scale", sm.NormalScale );

          // appliedMaterial.SetShaderParameter( "albedo_texture", sm.AlbedoTexture );
          // appliedMaterial.SetShaderParameter( "albedo_color", sm.AlbedoColor );
          // appliedMaterial.SetShaderParameter( "alpha_scissor_threshold", sm.AlphaScissorThreshold );
         
          // appliedMaterial.SetShaderParameter( "uv1_scale", sm.Uv1Scale );
          // appliedMaterial.SetShaderParameter( "uv1_offset", sm.Uv1Offset );

          // appliedMaterial.SetShaderParameter( "uncompressNormalMap", false );
          // appliedMaterial.SetShaderParameter( "useCustomNormals", true );
        }
        else
        {
          // n.LogInfo( "No StandardMaterial3D found", material.GetType().Name );
        }

        
        materials[ material ] = appliedMaterial;
      }

      
      Materials.Set( n, materials[ material ] );
    }

  }
}