
using Godot;
using System.Collections.Generic;
using System;
using System.Linq;
namespace Rokojori
{  
  [Tool]
  [GlobalClass]
  public partial class PostProcessVolumeEffect: Resource
  {
    public virtual void Apply( WorldEnvironment worldEnvironment )
    {

    }

    public virtual void Lerp( object listOfOwnType, List<PostProcessVolume> volumes )
    {
      
    }

    public virtual BoxedFloatValue[] GetFloatValues()
    {
      return [];
    }

    public virtual void SetFloatValues( BoxedFloatValue[] values )
    {

    }    

    public void LerpFloats( IReadOnlyList<PostProcessVolumeEffect> effects, List<PostProcessVolume> volumes)
    {
      var floatValues = GetFloatValues();

      for ( int i = 0; i < floatValues.Length; i++ )
      {
        if ( floatValues[ i ] == null )
        {
          var hasEffect = false;
          
          for ( int j = 0; j < effects.Count; j++ )
          {
            if ( effects[ j ].GetFloatValues() [ i ] != null )
            {
              hasEffect = true;
              j = effects.Count;
            }  
          }

          if ( hasEffect )
          {
            floatValues[ i ] = new FloatValue();
          }
          else
          {
            floatValues[ i ] = null;
          }
        }


        if ( floatValues[ i ] == null )
        {
          continue; 
        }

        floatValues[ i ].SetFloatValue( 0f );

      }

      var valueWeights = new float[ floatValues.Length ];
      var priorities   = new int[ floatValues.Length ];

      for ( int i = 0; i < floatValues.Length; i++ )
      {
        valueWeights[ i ] = 0;
        priorities[ i ] = -100000;
      }

      for ( int i = 0; i < effects.Count; i++ )
      {
        var otherValues = effects[ i ].GetFloatValues();

        // this.LogInfo( "effects:", HierarchyName.Of( effects[ i ] ) );

        for ( int j = 0; j < floatValues.Length; j++ )
        {
          if ( floatValues[ j ] == null || otherValues[ j ] == null )
          {
            continue; 
          }
          
          if ( volumes[ i ].priority < priorities[ j ] )
          {
            continue;
          }

          if ( priorities[ j ] < volumes[ i ].priority )
          {
            valueWeights[ j ] = 0f;
            floatValues[ j ].SetFloatValue( 0f );
          }

          priorities[ j ] = volumes[ i ].priority;  

          var value = floatValues[ j ].GetFloatValue();
          
          floatValues[ j ].SetFloatValue(  value + otherValues[ j ].GetFloatValue() );
          valueWeights[ j ] += volumes[ i ].combinedWeight;

          // this.LogInfo( "Lerping", j, otherValues[ j ].value, valueWeights[ j ] );
          
          
        }
      }

      for ( int i = 0; i < floatValues.Length; i++)
      {
        if ( floatValues[ i ] == null )
        {
          continue;
        }

        floatValues[ i ].SetFloatValue( floatValues[ i ].GetFloatValue() / valueWeights[ i ] );
      }

      SetFloatValues( floatValues );
    }

    public virtual ColorValue[] GetColorValues()
    {
      return [];
    }

    public virtual void SetColorValues( ColorValue[] values )
    {

    }    

    public void LerpColors( IReadOnlyList<PostProcessVolumeEffect> effects, List<PostProcessVolume> volumes)
    {
      var colorValues = GetColorValues();

      for ( int i = 0; i < colorValues.Length; i++ )
      {
        if ( colorValues[ i ] == null )
        {
          var hasEffect = false;
          
          for ( int j = 0; j < effects.Count; j++ )
          {
            if ( effects[ j ].GetColorValues() [ i ] != null )
            {
              hasEffect = true;
              j = effects.Count;
            }  
          }

          if ( hasEffect )
          {
            colorValues[ i ] = new ColorValue();
          }
          else
          {
            colorValues[ i ] = null;
          }
        }


        if ( colorValues[ i ] == null )
        {
          continue; 
        }

        colorValues[ i ].value = new Color( 0, 0, 0, 0 );

      }

      var valueWeights = new float[ colorValues.Length ];
      var priorities   = new int[ colorValues.Length ];

      for ( int i = 0; i < colorValues.Length; i++ )
      {
        valueWeights[ i ] = 0;
        priorities[ i ] = -100000;
      }

      for ( int i = 0; i < effects.Count; i++ )
      {
        var otherValues = effects[ i ].GetColorValues();

        // this.LogInfo( "effects:", HierarchyName.Of( effects[ i ] ) );

        for ( int j = 0; j < colorValues.Length; j++ )
        {
          if ( colorValues[ j ] == null || otherValues[ j ] == null )
          {
            continue; 
          }
          
          if ( volumes[ i ].priority < priorities[ j ] )
          {
            continue;
          }

          if ( priorities[ j ] < volumes[ i ].priority )
          {
            valueWeights[ j ] = 0f;
            colorValues[ j ].value = new Color( 0, 0, 0, 0 );
          }

          priorities[ j ] = volumes[ i ].priority;  
          
          colorValues[ j ].value += otherValues[ j ].value;
          valueWeights[ j ] += volumes[ i ].combinedWeight;

          // this.LogInfo( "Lerping", j, otherValues[ j ].value, valueWeights[ j ] );
          
          
        }
      }

      for ( int i = 0; i < colorValues.Length; i++)
      {
        if ( colorValues[ i ] == null )
        {
          continue;
        }

        colorValues[ i ].value /= valueWeights[ i ];
      }

      SetColorValues( colorValues );
    }
  }
}