
using System;
using Godot;


namespace Rokojori
{  
  [Tool]
  [GlobalClass, Icon("res://addons/rokojori_action_library/Icons/Tween.svg")]
  public partial class TweenAudio:SequenceAction, Animator
  {
    
    [Export]
    public AudioStreamPlayer3D target;

    [Export(PropertyHint.Range, "-80,80")]
    public float endVolumeDB;

    [Export]
    public bool tweenInLinearAmplitude = true;

    [Export]
    public bool changePlayState = true;

    [Export]
    public float changingPlayStateTresholdDB = -80f;

    [Export]
    public TweenType tweenType = new TweenTimeCurve();


    [Export]
    public bool cacheEndVolumeOnStart = true;

    [Export]
    public TimeLine timeLine;


    public void OnAnimatorStart(){}
    public void OnAnimatorEnd(){}
    public void OnAnimatorCancel(){}


    public float GetVolume( float volume )
    {
      if ( tweenInLinearAmplitude )
      {
        return MathAudio.DecibelsToAmplitude( volume );
      }

      return volume;
    }

    public float SetVolume( float volume )
    {
      if ( tweenInLinearAmplitude )
      {
        return MathAudio.AmplitudeToDecibels( volume );
      }

      return volume;    
    } 

  
    protected override void _OnTrigger()
    {
      if ( target == null )
      {
        return;
      }

      var tl = TimeLineManager.Ensure( timeLine );

      var start = tl.position;

      var fromVolume = GetVolume( target.VolumeDb );
      var toVolume = GetVolume( endVolumeDB ); 

      
      var sequenceID = DispatchStart(); 

      var tweenType = this.tweenType;

      if ( tweenType == null )
      {
        tweenType = TweenTimeCurve.defaultCurve;
      }      

      if ( changePlayState && toVolume > changingPlayStateTresholdDB )
      {
        // this.LogInfo( "Play" );
        target.Playing = true;
        target.Play( 0 );        
      }

      AnimationManager.StartAnimation( this, target, AnimationMember.VolumeDB );

      TimeLineManager.ScheduleSpanIn( tl, 0, tweenType.GetTweenDuration(), 
        ( span, type )=>
        {         
          if ( ! AnimationManager.IsAnimating( this, target, AnimationMember.VolumeDB ) )
          {
            return;
          }

          var timeNow = tl.position;
          var elapsed = timeNow - start;

          var state = tweenType.GetTweenPhaseForPhase( span.phase );

          if ( ! cacheEndVolumeOnStart )
          {
            toVolume = GetVolume( endVolumeDB ); 
          }

          var lerpedVolume = Mathf.Lerp( fromVolume, toVolume, state );

          target.VolumeDb = SetVolume( lerpedVolume );

          // this.LogInfo( "Volume", lerpedVolume );
         
          if ( type == TimeLineSpanUpdateType.End )
          {          
            DispatchEnd( sequenceID );

            AnimationManager.EndAnimation( this, target, AnimationMember.VolumeDB );

            if ( changePlayState && SetVolume( toVolume ) < changingPlayStateTresholdDB )
            {
              // this.LogInfo( "Stop" );
              target.Playing = false;
              target.Stop();              
            }
          }
        }
      );
    }

  }
}