using Godot;
using Rokojori;
using System.Collections.Generic;
using System;

namespace Rokojori
{ 

  [Tool]
  public class ActiveStyleTransition<V,P> 
  {
    public V value;
    public P propertyType;
    public TimeLine timeLine;
    public float start;
    public float end; 
    public Curve curve;
    public bool transitioning;

    public static O ProcessTransition<O>( 
      UIStylePropertyContainer container, O computedValue, 
      List<ActiveStyleTransition<V,P>> activeTransitions, V activeValue, P property,
      Func<TransitionSettingsAll> getTransitionSettings,
      Func<V,O> computeValue,
      Func<O,O,float,O> lerpValue 
      )
    {
      var propertyTransition = activeTransitions.Find( t => t != null && EqualityComparer<P>.Default.Equals( t.propertyType, property ) );

      if ( propertyTransition == null )
      {
        propertyTransition = new ActiveStyleTransition<V, P>();
        propertyTransition.propertyType = property;
        propertyTransition.value = activeValue;         
        propertyTransition.transitioning = false;

        activeTransitions.Add( propertyTransition );

        return computedValue;
      } 
      else
      {
        if ( ! EqualityComparer<V>.Default.Equals( propertyTransition.value, activeValue ) && 
        ! propertyTransition.transitioning && getTransitionSettings() != null )
        {
          var transitionSettings = getTransitionSettings();
          propertyTransition.timeLine = transitionSettings.timeLine;       
          propertyTransition.start = transitionSettings.timeLine.position;
          propertyTransition.end = propertyTransition.start + transitionSettings.duration;
          propertyTransition.transitioning = true;          
          propertyTransition.curve = transitionSettings.curve;
        }
      }

      if ( EqualityComparer<V>.Default.Equals( propertyTransition.value, activeValue ) )
      {
        propertyTransition.transitioning = false;
        return computedValue;
      }

      var computedTransitionValue = computeValue( propertyTransition.value );

      var transitionPhase = propertyTransition.timeLine.ComputeRange( propertyTransition.start, propertyTransition.end );
     
      if ( transitionPhase >= 1 )
      {
        activeTransitions.Remove( propertyTransition );
      }

      var amount = MathX.Clamp01( transitionPhase );
      var curveAmount = amount;

      if ( propertyTransition.curve != null )
      {
        curveAmount = propertyTransition.curve.Sample( curveAmount );
      }

      return lerpValue( computedTransitionValue, computedValue, curveAmount );
    }
  }
}