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

namespace Rokojori
{
  [Tool]
  [GlobalClass]
  public partial class MultiMeshGenerator:Node
  {
    [Export]
    public Node3D source;

    [Export]
    public Node3D output;

    [Export]
    public float blockSize = 50;

    [Export]
    public bool clearOutput = true;

    [Export]
    public bool update = false;

    public override void _Process( double delta ) 
    {
      if ( ! update )
      {
        return;
      }

      update = false;

      Generate();
    }




    public void Generate()  
    {
      if ( clearOutput )
      {
        Nodes.RemoveAndDeleteChildren( output );
      }

      var grid = Grid2D<MeshInstance3D>.XZfromNode3D<MeshInstance3D>( blockSize, blockSize );

      this.LogInfo( "Grid Created", grid );

      var instances = Nodes.AllIn<MeshInstance3D>( source );

      this.LogInfo( "Grabbed instances", instances.Count );

      grid.AddAll( instances );
      
      this.LogInfo( "Added instance to grid" );

      
      grid.ForEachCell( 
        ( cellID, list )  => 
        {
          var meshList = new MapList<Mesh,MeshInstance3D>();

          list.ForEach(
            ( n )=>
            {
              var m = n.Mesh;
              meshList.Add( m, n );
            }
          );

          var cIDCount = 0;
          meshList.ForEach(
            ( mesh, list ) =>
            {
              var cellIDInfo = "[" + cellID.X + "," + cellID.Y+"]";
              var mmi = output.CreateChild<LODMultiMesh>( "Cell" + cellIDInfo + "("  + cIDCount + ")" );

              var mm = new MultiMesh();
              mm.Mesh = mesh;
              
              mm.TransformFormat = MultiMesh.TransformFormatEnum.Transform3D;
              mm.InstanceCount = list.Count;
              mm.VisibleInstanceCount = list.Count;
              
              var random = new LCG();
              random.SetSeed( 12134 + (int)( Noise.Perlin( cellID ) * 10083 ) );

              var randomList = RandomList<MeshInstance3D>.Randomize( list, random );

              var center = Math3D.Center( randomList );

              mmi.GlobalPosition = center;

              for ( int i = 0; i < randomList.Count; i++ )
              {
                var trsf = randomList[ i ].GlobalTransform;
                trsf.Origin -= center;

                mm.SetInstanceTransform( i, trsf );
              }

              mmi.Multimesh = mm;

              mmi.CacheTransforms();

              Materials.Set( mmi, Materials.Get<Material>( list[ 0 ] ) );

              cIDCount++;
            }
          );
        }
      );
      

    } 
  }
}