using Godot;
using System.Reflection;
using System.Collections.Generic;
using System.Text;

namespace Rokojori
{ 
  public class WaveTable:iPhaseGenerator
  { 
    float[] _samples = new float[ 0 ];

    public float[] samples => _samples;

    public void SetPitchRange( float minPitch, float maxPitch )
    {
      
    }

    public float Get( float phase )
    {
      var samplePosition = phase * _samples.Length;
      samplePosition = MathX.Repeat( samplePosition, _samples.Length );

      var l = (int) samplePosition;
      var h = MathX.Repeat( l + 1, _samples.Length );

      var lerp = samplePosition - l;
      
      return Mathf.Lerp( _samples[ l ], _samples[ h ], lerp );  
      
    }

    public static WaveTable FromSamples( float[] samples )
    {
      var wt = new WaveTable();
      wt._samples = samples;

      return wt;
    }

    public void Normalize()
    {
      var max = 0f;

      for ( int  i = 0; i < _samples.Length; i++ )
      {
        max = Mathf.Max( Mathf.Abs( _samples[ i ] ), max );
      }
    
      for ( int  i = 0; i < _samples.Length; i++ )
      {
        _samples[ i ] = _samples[ i ] / max;
      }
    }

    public static WaveTable FromSines( Vector2[] magnitudesAndPhases, float filterStart = -1, float filterEnd = -1, int size = 4096 )
    {

      var fftReal      = new float[ size ];
      var fftImaginary = new float[ size ];

      var hasNoFilter = ( filterStart == -1 && filterEnd == -1 );
      
      
      for ( int i = 0; i < magnitudesAndPhases.Length; i++ )
      {
        var filter = hasNoFilter ? 1 : ( 1f - MathX.NormalizeClamped( i, filterStart, filterEnd ) );

        fftReal[ i ]      = Mathf.Cos( magnitudesAndPhases[ i ].Y ) * magnitudesAndPhases[ i ].X * filter;
        fftImaginary[ i ] = Mathf.Sin( magnitudesAndPhases[ i ].Y ) * magnitudesAndPhases[ i ].X * filter;
      }

      
      FFT.Inverse( size, fftReal, fftImaginary );

      return FromSamples( fftReal );
    }
  }
}