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



namespace Rokojori
{
  /** <summary for="class FoliageRenderLayer">
      
      <title>
        Is used by the FoliageRenderer to book keep and render a layer defined by the FoliageData.
        
      </title>
      
      <description>
               

      </description>

    </summary>  
  */

  public class FoliageRenderLayer
  {
    public FoliageRenderer renderer;
    public FoliageData data;
    public int subLayerIndex = -1;
    public GpuParticles3D gpuParticles3D;
    public GPUFoliageShaderMaterial gpuFoliageShaderMaterial;
    float _lastCellSize = -1;
    float _lastMaxVisibility = -1;

    public static FoliageRenderLayer Create( FoliageRenderer renderer, FoliageData data, int subIndex = -1 )
    {
      var rl = new FoliageRenderLayer();
      rl.renderer = renderer;
      rl.data = data;
      rl.subLayerIndex = subIndex;
     

      return rl;
    }

    bool _isEnabled = false;

    public void Update( double delta )
    {
      if ( gpuFoliageShaderMaterial == null )
      {
        return;
      }

      if ( data.enabled != _isEnabled)
      {
        _isEnabled = data.enabled;
        gpuParticles3D.SetEnabledState( _isEnabled );
        return;
      }

      if ( ! _isEnabled )
      {
        return;
      }

      gpuFoliageShaderMaterial.cameraPosition.Set( renderer.GetAssignedCamera().GlobalPosition );

      if ( ! data.updateSettings )
      {
        return;
      }

      UpdateProcessMaterial();

      

      data.materialOverride?.UpdateFoliageOverideMaterial( this );

      var material = data.materialOverride != null ? 
                      data.materialOverride.GetOverrideMaterial( this ) : 
                      gpuParticles3D.DrawPass1.SurfaceGetMaterial( 0 );

      data.materialOverride?.translucencySettings?.ApplyTranslucency( material, this );


      // if ( data.overwriteAlphaScissorToDepthPrepass && gpuParticles3D.DrawPass1.SurfaceGetMaterial( 0 ) is StandardMaterial3D standardDrawMaterial )
      // {
      //   if ( BaseMaterial3D.TransparencyEnum.AlphaScissor == standardDrawMaterial.Transparency  )
      //   {
      //     var overrideMaterial = (StandardMaterial3D) standardDrawMaterial.Duplicate();
      //     overrideMaterial.Transparency = BaseMaterial3D.TransparencyEnum.AlphaDepthPrePass;
      //     gpuParticles3D.MaterialOverride = overrideMaterial;
      //     overrideMaterial.RenderPriority = data.renderPriority;
      //   }         

      // }

      // if ( gpuParticles3D.DrawPass1.SurfaceGetMaterial( 0 ) is ShaderMaterial drawMaterial )
      // {
      //   drawMaterial.RenderPriority = data.renderPriority;

      //   drawMaterial.SetShaderParameter( "obstacle1", renderer.GetObstacleData( 0 ) );
      //   drawMaterial.SetShaderParameter( "obstacle2", renderer.GetObstacleData( 1 ) );
      //   drawMaterial.SetShaderParameter( "obstacle3", renderer.GetObstacleData( 2 ) );
      //   drawMaterial.SetShaderParameter( "obstacle4", renderer.GetObstacleData( 3 ) );

      //   // RJLog.Log( drawMaterial, renderer.GetObstacleData( 0 ) );
      // }

      
    } 

    void UpdateProcessMaterial()
    {
      var cellSize = FoliageQualitySettings.GetCellSize( renderer.quality, renderer.qualitySettingsAll, data.qualitySettings, data.GetCellSize( subLayerIndex ) );
      var visibilityRange =  FoliageQualitySettings.GetVisibilityRange( renderer.quality, renderer.qualitySettingsAll, data.qualitySettings, data.GetVisibilityRange( subLayerIndex ) );
      
      var sizeInt = Mathf.CeilToInt( visibilityRange / cellSize ) * 2;

      if ( _lastCellSize != cellSize || _lastMaxVisibility != visibilityRange )
      {
        _lastCellSize = cellSize;
        _lastMaxVisibility = visibilityRange;

        gpuFoliageShaderMaterial.cellSize.Set( cellSize );    

        gpuParticles3D.Amount = sizeInt * sizeInt;
        gpuFoliageShaderMaterial.width.Set( sizeInt );
        gpuFoliageShaderMaterial.height.Set( sizeInt );

      }

      var hideStart = visibilityRange - ( visibilityRange * data.GetVisibilityFadeRelative( subLayerIndex ) + data.GetVisibilityFadeAbsolute( subLayerIndex ) );
      gpuFoliageShaderMaterial.hideMax.Set( visibilityRange );
      gpuFoliageShaderMaterial.hideStart.Set( hideStart );
      gpuFoliageShaderMaterial.hideOffset.Set( data.GetVisibilityFadeHidingOffset( subLayerIndex ) ); 

      gpuFoliageShaderMaterial.positionVariance.Set( renderer.noise );
      gpuFoliageShaderMaterial.rotationVariance.Set( renderer.noise );
      gpuFoliageShaderMaterial.scaleVariance.Set( renderer.noise );
      gpuFoliageShaderMaterial.occupancyVariance.Set( renderer.noise );

      gpuFoliageShaderMaterial.maxPositionOffset.Set( data.positionVarianceAbsoluteOffset + data.positionVarianceCellSizeRelativeOffset * cellSize );
      gpuFoliageShaderMaterial.positionOffset.Set( data.GetPositionOffset( subLayerIndex ) );
      gpuFoliageShaderMaterial.positionUvScale.Set( Vector2.One * data.positionVarianceScale );
      gpuFoliageShaderMaterial.positionUvOffset.Set( Vector2.One * data.positionVarianceOffset );

      gpuFoliageShaderMaterial.minRotation.Set( data.rotationMin );
      gpuFoliageShaderMaterial.maxRotation.Set( data.rotationMax );
      gpuFoliageShaderMaterial.rotationUvScale.Set( Vector2.One * data.rotationVarianceScale );
      gpuFoliageShaderMaterial.rotationUvOffset.Set( Vector2.One * data.rotationVarianceOffset );

      gpuFoliageShaderMaterial.minScale.Set( data.scaleVarianceMinScale );
      gpuFoliageShaderMaterial.maxScale.Set( data.scaleVarianceMaxScale );
      gpuFoliageShaderMaterial.scaleUvScale.Set( Vector2.One * data.scaleVarianceScale );
      gpuFoliageShaderMaterial.scaleUvOffset.Set( Vector2.One * data.scaleVarianceOffset );

      gpuFoliageShaderMaterial.occupancyAmount.Set( data.occupancyVarianceAmount );
      gpuFoliageShaderMaterial.occupancyPower.Set( data.occupancyVariancePower );
      gpuFoliageShaderMaterial.occupancyTreshold.Set( data.occupancyTreshold );

      gpuFoliageShaderMaterial.occupancyHideOffset.Set( data.occupancyHideOffset );
      gpuFoliageShaderMaterial.occupancyHideScale.Set( data.occupancyHideScale );

      gpuFoliageShaderMaterial.occupancyUvScale.Set( Vector2.One * data.occupancyVarianceScale );
      gpuFoliageShaderMaterial.occupancyUvOffset.Set( Vector2.One * data.occupancyVarianceOffset );

      if ( data.GetSort( subLayerIndex ) )
      {
        gpuParticles3D.DrawOrder = GpuParticles3D.DrawOrderEnum.ViewDepth;
      }
    }
  }
}