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



namespace Rokojori
{
  /** <summary for="class FoliageData">
      
      <title>
        Resource to define foliage data
      </title>
      
      <description>
        
      </description>

    </summary>  
  */

  [Tool]
  [GlobalClass, Icon("res://addons/rokojori_action_library/Icons/Scatterer.svg") ]
  public partial class FoliageData:Resource
  {

    [Export]
    public string layerName;


    [Export]
    public bool enabled = true;

    [Export]
    public bool updateSettings = true;

    [Export]
    public FoliageQualitySettings[] qualitySettings;


    [ExportGroup("Visibility")]

    [Export]
    public float cellSize = 1.0f;

    public float GetCellSize( int subLayerIndex = -1 )
    {
      if ( subLayerIndex < 0 )
      {
        return cellSize;
      }

      var subLayer = subLayers[ subLayerIndex ];

      return subLayer.cellSizeOffset + subLayer.relativeCellSize * cellSize;
    }

    [Export]
    public float visibilityRange = 50f;

    public float GetVisibilityRange( int subLayerIndex = -1 )
    {
      if ( subLayerIndex < 0 )
      {
        return visibilityRange;
      }

      var subLayer = subLayers[ subLayerIndex ];

      return subLayer.additionalVisibilityRange + subLayer.relativeVisibilityRange * visibilityRange;
    }

    [Export]
    public float visibilityFadeRelative = 0.5f;

    public float GetVisibilityFadeRelative( int subLayerIndex = -1 )
    {
      if ( subLayerIndex < 0 )
      {
        return visibilityFadeRelative;
      }

      var subLayer = subLayers[ subLayerIndex ];

      return subLayer.visibilityFadeRelative;
    }

    [Export]
    public float visibilityFadeAbsolute = 0f;

    public float GetVisibilityFadeAbsolute( int subLayerIndex = -1 )
    {
      if ( subLayerIndex < 0 )
      {
        return visibilityFadeAbsolute;
      }

      var subLayer = subLayers[ subLayerIndex ];

      return subLayer.visibilityFadeAbsolute;
    }

    [Export]
    public float visibilityFadeHidingOffset = -0.7f;

    public float GetVisibilityFadeHidingOffset( int subLayerIndex = -1 )
    {
      if ( subLayerIndex < 0 )
      {
        return visibilityFadeHidingOffset;
      }

      var subLayer = subLayers[ subLayerIndex ];

      return visibilityFadeHidingOffset + subLayer.additionalVisibilityFadeHidingOffset;
    }


    [ExportGroup("Model")]
    [Export]
    public FoliageSource source;

    [ExportGroup("Renderer")]

    [Export]
    public FoliageMaterialOverride materialOverride;

    /** <summary for="field renderPriority">Render priority, only for transparent objects</summary>*/
    [Export]
    public FoliagePriority renderPriority;

    [Export]
    public bool shadows = true;

    public bool GetShadows( int subLayerIndex )
    {
      if ( subLayerIndex < 0 )
      {
        return shadows;
      }

      var subLayer = subLayers[ subLayerIndex ];

      return subLayer.shadows;
    }

    [Export]
    public bool sort = false;

    public bool GetSort( int subLayerIndex )
    {
      if ( subLayerIndex < 0 )
      {
        return sort;
      }

      var subLayer = subLayers[ subLayerIndex ];

      return subLayer.sort;
    }
    
    [ExportGroup("Sub Layers")]
    [Export]
    public SubFoliageData[] subLayers = [];

    public int numLayers
    {
      get 
      {
        var num = 1;
        for ( int i = 0; subLayers != null && i < subLayers.Length; i++ )
        {
          if ( subLayers[ i ] == null )
          {
            continue;
          }
          num++;
        }

        return num;
      }
    }

    [ExportGroup("Position")]
    [Export]
    public Vector3 positionVarianceAbsoluteOffset = Vector3.Zero;

    [Export]
    public Vector3 positionVarianceCellSizeRelativeOffset = Vector3.Zero;

    [Export]
    public Vector3 positionOffset = Vector3.Zero;

    public Vector3 GetPositionOffset( int subLayerIndex )
    {
      if ( subLayerIndex < 0 )
      {
        return positionOffset;
      }

      var subLayer = subLayers[ subLayerIndex ];

      return positionOffset + subLayer.subPositionOffset;
    }

    [Export]
    public float positionVarianceScale = 1f;
    [Export]
    public Vector2 positionVarianceOffset = Vector2.Zero;

    [ExportGroup("Rotation")]

    [Export]
    public Vector3 rotationMin = Vector3.Zero;
    [Export]
    public Vector3 rotationMax = new Vector3( 0, 1, 0 );

    [Export]
    public float rotationVarianceScale = 1f;
    [Export]
    public Vector2 rotationVarianceOffset = Vector2.Zero;


    [ExportGroup("Scale")]
    [Export]
    public float uniScaleMin = 1.0f;

    [Export]
    public float uniScaleMax = 1.0f;

    [Export]
    public float uniScaleVarianceContrastScale = 1f;

    [Export]
    public float uniScaleVarianceContrastCenter = 0.5f;

    [Export]
    public Vector2 uniScaleVarianceOffset = new Vector2( 0.5f, 0.5f );

    [Export]
    public Vector3 scaleVarianceMinScale = Vector3.One;
    [Export]
    public Vector3 scaleVarianceMaxScale = Vector3.One;

    [Export]
    public float scaleVarianceScale = 1f;
    [Export]
    public Vector2 scaleVarianceOffset = Vector2.Zero;

    [ExportGroup("Occupancy")]
    [Export(PropertyHint.Range,"0,1")]
    public float occupancyVarianceAmount = 0f;
    [Export(PropertyHint.Range,"0,50")]
    public float occupancyVariancePower = 1f;

    [Export(PropertyHint.Range,"0,1")]
    public float occupancyTreshold = 0.5f;

    [Export]
    public float occupancyHideOffset = -2f;
    [Export]
    public float occupancyHideScale = 0.1f;

    [Export]
    public float occupancyVarianceScale = 1f;
    
    [Export]
    public Vector2 occupancyVarianceOffset = Vector2.Zero;

    [ExportGroup("Colliders")]

    [Export]
    public bool collidersEnabled = false;

    [Export]
    public int numMaxColliders = 0;

    [Export]
    public Shape3D colliderShape;

    [Export]
    public Vector3 colliderOffset = Vector3.Zero;

    [Export]
    public float colliderCellSize = 50f;

    [Export]
    public float colliderScaleOffset = 1.0f;
    
    [Export]
    public bool updateCollidersAlways = false;

    public virtual void Initialize( FoliageRenderLayer renderLayer )
    {
      var particles = renderLayer.renderer.CreateChild<GpuParticles3D>( renderLayer.data.layerName );

      if ( collidersEnabled )
      {
        renderLayer.collidersContainer = particles.CreateChild<Node3D>( "Colliders" );
      }

      renderLayer.gpuParticles3D = particles;

      var processMaterial = new GPUFoliageShaderMaterial();
      particles.ProcessMaterial = processMaterial;
      particles.Lifetime = 0.01f;
      particles.Explosiveness = 1f;
      particles.FixedFps = 0;
      particles.Interpolate = false;
      particles.FractDelta = false;

      particles.CustomAabb = Box3.WithSize( 10000 );
      particles.CastShadow = renderLayer.data.GetShadows( renderLayer.subLayerIndex ) ? GeometryInstance3D.ShadowCastingSetting.On : GeometryInstance3D.ShadowCastingSetting.Off;
      

      // processMaterial.positionVariance.Set( renderLayer.renderer.noise );
      // processMaterial.rotationVariance.Set( renderLayer.renderer.noise );
      // processMaterial.scaleVariance.Set( renderLayer.renderer.noise );
      // processMaterial.occupancyVariance.Set( renderLayer.renderer.noise );

      renderLayer.gpuFoliageShaderMaterial = processMaterial;

      
      source?.SetupFoliageDrawPass( renderLayer );
      materialOverride?.CreateFoliageOverideMaterial( renderLayer );
      
    }

  }
}