


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

namespace Rokojori
{ 
  [Tool]
  [GlobalClass,Icon("res://addons/rokojori_action_library/Icons/UIImage.svg")]
  public partial class UISlider:UIImage
  { 
    public enum Direction
    {
      Vertical,
      Horizontal,
      Both
    }

    [Export]
    public Direction direction = Direction.Vertical;

    [Export]
    public Smoothing smoothing;

    Vector2 _sliderValue;

    [Export]
    public Vector2 sliderValue
    {
      get { return _sliderValue; }
      set 
      {
        _sliderValue = value;
        SyncSliderValue();
      }
    }

    void SyncSliderValue()
    {
      SliderShader.sliderValue.Set( Material, sliderValue );
    }

    public override void _Ready()
    {
      base._Ready();

      if ( imageType == null )
      {
        imageType = new SliderUIImageType();
      }

      if ( Texture == null )
      {
        Texture = UI.whiteTexture.Get();
      }
      
      var uiSliderImageType = _imageType as SliderUIImageType;

      if ( uiSliderImageType != null )
      {
        uiSliderImageType.Clear( this );
        uiSliderImageType.Assign( this );

      }

      ComputeUIAncestorDepth();

      SyncSliderValue();


      AssignListener();
    }

    [Export]
    public bool debugInfo = false;

    [Export]
    public string[] propertyInfos = [];

    public override void _Process( double delta )
    {
      if ( ! debugInfo )
      {
        return;
      }

      var it = imageType as SliderUIImageType;

      if ( it == null )
      {
        return;
      }

      var propNames = it.GetNumberShaderProperties();

      var tw = Texture.GetWidth();
      var th = Texture.GetHeight();

      var w = UINumber.Compute( this, UIStyleNumberProperty.Width, tw, tw / 100f );
      var h = UINumber.Compute( this, UIStyleNumberProperty.Height, th, th / 100f );

      var infos = new List<string>();
      for ( int i = 0; i < propNames.Length; i++ )
      {
        var n = propNames[ i ];
        var p = it.GetUIStyleNumberProperty( UIStyleNumberProperty.FloatShaderProperty, n );

        if ( p == null )
        {
          continue;
        }

        var relative = 100f;
        
        if ( n.EndsWith( ".x" ) )
        {
          relative = w;
        }
        else if ( n.EndsWith( ".y" ) )
        {
          relative = h;
        }


        var value = UINumber.Compute( this, UIStyleNumberProperty.FloatShaderProperty, n, 0, relative );
        infos.Add( "[" + n + "] (" + p.value._FFF() + " * " + p.unit +") :" + value._FFF() );
      }

      propertyInfos = infos.ToArray();

      this.LogInfo( propertyInfos );


      debugInfo = false;
      
    }



    UIDragging.UIDraggingCallbacks leftMouseCallbacks;
    Vector2 cachedMouseOffset;
    Vector2 cachedButtonPosition;

    bool _dragging = false;
    bool _updatingPosition = false;

    string scrollID = IDGenerator.GenerateID();

    float ComputeShaderProperty( string n, float relative = 100 )
    {
      return UINumber.Compute( this, UIStyleNumberProperty.FloatShaderProperty, n, 0, relative );
    }

    Vector2 sliderSize 
    {
      get 
      {
        var tw = Texture.GetWidth();
        var th = Texture.GetHeight();

        var w = UINumber.Compute( this, UIStyleNumberProperty.Width, tw, tw / 100f );
        var h = UINumber.Compute( this, UIStyleNumberProperty.Height, th, th / 100f );

        var valueX = ComputeShaderProperty( SliderShader.sliderSize.propertyNameX, w );
        var valueY = ComputeShaderProperty( SliderShader.sliderSize.propertyNameY, h );

        return new Vector2( valueX, valueY );
      }
    }

    Vector2 sliderSizeMargins
    {
      get 
      {
        var tw = Texture.GetWidth();
        var th = Texture.GetHeight();

        var w = UINumber.Compute( this, UIStyleNumberProperty.Width, tw, tw / 100f );
        var h = UINumber.Compute( this, UIStyleNumberProperty.Height, th, th / 100f );

        var valueX = ComputeShaderProperty( SliderShader.sliderSizeMargins.propertyNameX, w );
        var valueY = ComputeShaderProperty( SliderShader.sliderSizeMargins.propertyNameY, h );

        return new Vector2( valueX, valueY );
      }
    }

    Vector2 sliderRange => Size - ( sliderSize + sliderSizeMargins );
    Vector2 sliderOffset => sliderSize;
    
    Vector2 buttonPositionMin
    {
      get { return NormalizedToButtonPosition( Vector2.Zero ); }
    }

    Vector2 buttonPositionMax
    {
      get { return NormalizedToButtonPosition( Vector2.One ); }
    }


    Vector2 NormalizedToButtonPosition( Vector2 normalized )
    {
      return normalized * sliderRange + sliderOffset;
    }

    Vector2 ButtonPositionToNormalized( Vector2 buttonPosition )
    {
      return ( buttonPosition - sliderOffset ) / sliderRange;
    }


    bool _listenerAssigned = false;

    void AssignListener()
    {
      if ( _listenerAssigned )
      {
        return;
      }

      leftMouseCallbacks = UIDragging.OnLeftMouseButton( this,
        ( ev )=>
        {
          if ( ev.isStart )
          { 
            cachedButtonPosition = NormalizedToButtonPosition( sliderValue );
            smoothing.SetCurrent( cachedButtonPosition );

            _dragging = true;
            _updatingPosition = true;

            ev.ui.onProcess.AddAction( UpdatePosition );
          } 
          else if ( ev.isEnd )
          {
            _dragging = false;
          }

          var nextPosition = cachedButtonPosition + ev.distanceToStart;
          nextValue = nextPosition.Clamp( buttonPositionMin, buttonPositionMax );                 
        
        }
      );

      _listenerAssigned = true;
    }

    Vector2 nextValue;

    Vector2 GetButtonScrollRange()
    {
      return Vector2.Zero;
      // return ( Size - button.Size ).Max( Vector2.Zero );
    }

    Vector2 cachedOffset = Vector2.Zero;

    void UpdatePosition( float delta )
    {
      // this.LogInfo( "UpdatePosition" );
      var value = Smoothing.Apply( smoothing, nextValue, delta );

      var uiStyleContainer = ( UIStylePropertyContainerNode ) this;
      
      uiStyleContainer.SetLayoutDirtyFlag();

      if ( ! _dragging && ( value - nextValue ).Length() < 1 )
      { 
        var ui = UIHolder.GetUI( this );
        ui.onProcess.RemoveAction( UpdatePosition );
        _updatingPosition = false;
        // this.LogInfo( "Removed Processing" );

        value = nextValue;

        uiStyleContainer.RemoveUISelectorFlag( UISelectorFlag.Scrolling, scrollID );
        
      }

  	  var currentSliderValue = ButtonPositionToNormalized( value );

      if ( Direction.Vertical == direction )
      {
        currentSliderValue.X = 0.5f;
      }
      else if ( Direction.Vertical == direction )
      {
        currentSliderValue.Y = 0.5f;
      }

      _sliderValue = currentSliderValue;
      SyncSliderValue();
      
    }

  }
}