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



namespace Rokojori
{
  /** <summary for="class FoliageRenderer">
      
      <title>
        A node to render foliage.
      </title>
      
      <description>
        The GrassPatch has various settings to create a different styles of grass.
        It allows to change the shapes of the blades, their number and distribution, their triangle count,
        rotation and scale, LOD levels and much more. 
        

      </description>

    </summary>  
  */

  [Tool]
  [GlobalClass, Icon("res://addons/rokojori_action_library/Icons/Scatterer.svg") ]
  public partial class FoliageRenderer:Node3D
  {
    [ExportToolButton( "Update Layers" )]
    public Callable updateLayersButton => Callable.From( ()=> updateLayers = true ) ;

    [Export]
    public FoliageData[] foliage = [];

    
    [ExportGroup("Quality")]
    [Export( PropertyHint.Range, "0, 200" )]
    public float quality = 100;

    [Export]
    public FoliageQualitySettings[] qualitySettingsAll;

    [ExportGroup("Shared")]

    [Export]
    public Camera3D camera;

    public override void _Ready()
    {
      updateLayers = true;
    }

    [Export]
    public Vector2 globalMapSizeXZ;

    [Export]
    public Vector2 globalMapCenterXZ;

    [ExportGroup("Shared/Region")]
    [Export]
    public bool trimToRegion = false;

    [Export]
    public Vector2 regionSizeXZ;

    [Export]
    public Vector2 regionCenterXZ;

    [ExportGroup("Shared")]

    [Export]
    public Texture2D heightMap;

    [Export]
    public float minHeight = 0;

    [Export]
    public float maxHeight = 100;

    [Export]
    public float snapDistance = 50;

    [Export]
    public Texture2D normalMap;

    [Export]
    public Texture2D coverageMap;

    [Export]
    public Texture2D colorMap;

    [Export]
    public Texture2D noise;

    [Export]
    public int renderPriorityOffset = 0;
    

    [ExportGroup("Obstacles")]
    [Export]
    public Node3D[] obstacles = [];

    [Export]
    public float[] obstacleSizes = [];

    Vector4[] obstaclesData = new Vector4[4];

    public Vector4 GetObstacleData( int index )
    {
      return obstaclesData[ index ];
    }
   
    List<FoliageRenderLayer> renderLayers = [];

    [Export]
    public bool processLayers = true;

    public bool updateLayers = true;

    Camera3D _assignedCamera;



    public Camera3D GetAssignedCamera()
    {
      return _assignedCamera;  
    }

    public int numFoliageLayers
    {
      get 
      { 
        var numLayers = 0;

        foliage.ForEach( fd => numLayers += fd == null ? 0 : fd.numLayers );

        return numLayers;
      }
      
    }

    Dictionary<Texture2D,TextureCombinerBuffer> _buffer = new Dictionary<Texture2D, TextureCombinerBuffer>();

    Dictionary<Texture2D,Image> _bufferedImages = new Dictionary<Texture2D, Image>();

    // public Color 
    // public TextureCombinerBuffer GetTextureBuffer( Texture2D texture2D )
    // {
    //   texture2D.GetImage()
    //   // if ( ! _bufferedImages.ContainsKey( texture2D ) )
    //   // {
    //   //   // var tcb = TextureCombinerBuffer.From( texture2D );
    //   //   // _buffer[ texture2D ] = tcb;

    //   //   var image = texture2D.GetImage();
    //   //   image.GetPixel
    //   // }

    //   // return _buffer[ texture2D ];
    // }

    public override void _Process( double delta )
    {
      _assignedCamera = null;

      if ( ! processLayers || foliage == null || foliage.Length == 0 )
      {
        return;
      }

      

      if ( updateLayers || numFoliageLayers != renderLayers.Count )
      {
        updateLayers = false;
        this.DestroyChildren();

        renderLayers = new List<FoliageRenderLayer>();
        foliage.ForEach(
          ( fd )=>
          {
            renderLayers.Add(  FoliageRenderLayer.Create( this, fd ) );

            for ( int i = 0; fd.subLayers != null && i < fd.subLayers.Length; i++ )
            {
              if ( fd.subLayers[ i ] == null )
              {
                continue;
              }

              renderLayers.Add(  FoliageRenderLayer.Create( this, fd, i ) );
            }
          }
        );

        this.LogInfo( "Initialize:", renderLayers.Count );
        renderLayers.ForEach( r => r.data.Initialize( r ) );

      }

      if ( obstaclesData.Length != 4 )
      {
        obstaclesData = new Vector4[ 4];
      } 

      for ( int i = 0; i < obstaclesData.Length; i++ )
      {
        var position = obstacles == null || i >= obstacles.Length  ? Vector3.Zero : obstacles[ i ].GlobalPosition; 
        var size     = obstacleSizes == null || i >= obstacleSizes.Length  ? 0 : obstacleSizes[ i ];  

        obstaclesData[ i ] = new Vector4( position.X, position.Y, position.Z, size ); 
      }


      if ( Engine.IsEditorHint() )
      {
        _assignedCamera = EditorInterface.Singleton.GetEditorViewport3D().GetCamera3D();
      }
      else
      {
        _assignedCamera = camera;
      }

      if ( _assignedCamera == null )
      {
        return;
      }


      // this.LogInfo( "Processing", renderLayers.Count );

      renderLayers.ForEach( r => 
        {
          if ( r == null ) 
          { 
            return; 
          } 
          
          r.Update( delta );
        }
      );
    }

  }
}