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



namespace Rokojori
{
  [Tool]
  [GlobalClass, Icon("res://addons/rokojori_action_library/Icons/Scatterer.svg") ]
  public partial class BillboardTree:Node3D
  {
    float _startHeight = 2;
    [Export]
    public float startHeight 
    {
      get => _startHeight;
      set { _startHeight = value; }
    }

    float _endHeight = 7;
    [Export]
    public float endHeight 
    {
      get => _endHeight;
      set { _endHeight = value; }
    }

    [Export]
    public Curve radiusShape;
  	
    [Export]
    public MeshInstance3D leavesMesh;
    
    [Export]
    public Material leavesMaterial;

    [Export]
    public int numRows = 5;

    [Export]
    public Curve rowDensity = MathX.Curve( 0.2f, 0.8f ); 

    [Export]
    public Curve leavesSize = MathX.Curve( 0.2f, 0.8f );

    [Export]
    public Curve leavesRotation = MathX.Curve( 0f, 360f );

    [Export]
    public int seed = 2000;

    
    MeshGeometry mg;
    RandomEngine random;

    
    [Export]
    public bool update = false;

    [Export]
    public bool updateAlways = false;


    public override void _Process( double d )
    { 
      if ( ! ( updateAlways || update ) )
      {
        return;
      }

      update = false;

      Generate();
    }

    void Generate()
    {
      if ( leavesMesh == null )
      {
        leavesMesh = this.CreateChild<MeshInstance3D>( "Leaves" );
      }

      mg = new MeshGeometry();      
      random = LCG.WithSeed( seed );


      for ( int i = 0; i < numRows; i++ )
      {
        CreateRow( i );
      }


      leavesMesh.Mesh = mg.GenerateMesh();

      Materials.Set( leavesMesh, leavesMaterial );
    }

    void CreateRow( int rowIndex )
    {
      
      var rowNormalized = rowIndex / (float) ( numRows - 1 );
      var rowRadius = radiusShape.Sample( rowNormalized );
      var rowDensityValue = random.Sample( rowDensity );
      var numLeaves = Mathf.Ceil( rowRadius / rowDensityValue );

      var rowAngleOffset = random.Range( 0, 360f );

      //this.LogInfo( "index:", rowIndex, "leaves:", numLeaves );

      for ( int i = 0; i < numLeaves; i++ )
      {
        var size =  random.Sample( leavesSize );
        var leave = MeshGeometry.BillboardQuad( size );

        var angle = 360f * i / ( (float) numLeaves ) + rowAngleOffset;

        

        var position = Math3D.OnCircleXZ( MathX.DegreesToRadians * angle ) * rowRadius;
        position.Y = Mathf.Lerp( startHeight, endHeight, rowNormalized );      

        var rotation = random.Sample( leavesRotation );
        //this.LogInfo( "index:", rowIndex, "leaves:", numLeaves, i, "size/angle", size, "/", angle, "pos:", position.X, position.Z );

        leave.ApplyTransform( position, Math3D.RotateZ( MathX.DegreesToRadians * rotation ), Vector3.One );         

        var normal = position - new Vector3( 0, ( startHeight + endHeight ) / 2f, 0);
        normal = normal.Normalized();

        this.LogInfo( "index:", rowIndex, "leaves:", numLeaves, i, normal );

        mg.Add( leave );
        mg.NormalsLookAt( normal, 1 );

        var clone = leave.Clone();
        clone.FlipNormalDirection();
        clone.NormalsLookAt( normal, 1 );

        mg.Add( clone );
      }
    }

  }
}