
using Godot;
using System;
using System.IO;

namespace Rokojori
{ 
  [Tool][GlobalClass] 
  public partial class OldUISlider : Node, IAssemblyReload
  { 
    
    [Export]
    public Control button;

    [Export]
    public Control background;

    [Export]
    public Smoothing smoothing;

    public enum Direction
    {
      Vertical,
      Horizontal,
      Both
    }

    [Export]
    public Direction direction = Direction.Vertical;

    [Export]
    public Vector2 sliderValue;

    [ExportGroup( "Scrolling")]
    [Export]
    public Control scrollTarget;    
    [Export]
    public Control scrollContainer;

    [Export]
    public bool adjustButtonSizeToScrollContent;

    [Export( PropertyHint.Range, "0,500, suffix:px")]
    public float mouseWheelAbsoluteScroll = 10f;

    [Export( PropertyHint.Range, "0,100, suffix:%")]
    public float mouseWheelRelativeScroll = 10f;
    
    Vector2 cachedMouseOffset;
    Vector2 cachedButtonPosition;

    public void OnAssemblyReloaded()
    {
      AddDraggingListener();
    }

    string scrollID = IDGenerator.GenerateID();

    public override void _Ready()
    {
      // button.GuiInput += OnGUIInput;

      // this.LogInfo( "S Adding new listeners" );
      AddDraggingListener();

      if ( scrollTarget != null && scrollContainer != null )
      {
        scrollContainer.Resized += SyncScroll;

        scrollContainer.GuiInput += ( InputEvent ie )=>
        {
          
          if ( ie is InputEventMouseButton mb && 
           (  mb.ButtonIndex == MouseButton.WheelUp || mb.ButtonIndex == MouseButton.WheelDown ||
           mb.ButtonIndex == MouseButton.WheelLeft || mb.ButtonIndex == MouseButton.WheelRight )
          )
          { 
            var range = GetScrollRange();
            // var percentageAmount = 0.1f;
            // var relativeToAbsolute = percentageAmount * range;
            var absoluteAmount = mouseWheelAbsoluteScroll;
            var absoluteToRelative = mouseWheelAbsoluteScroll * Vector2.One / range;
            var buttonRange = absoluteToRelative * GetButtonScrollRange();

            var scrollDelta = buttonRange;

            // this.LogInfo( leftMouseCallback == null, leftMouseCallback?.GetUID(), leftMouseCallback?.GetInfo(), leftMouseCallback?.wasDisposed );
            

            // scrollContainer.LogInfo( "Input", ie );

            if ( mb.ButtonIndex == MouseButton.WheelUp )
            {
              scrollDelta.Y *= -1;
            }

            if ( mb.ButtonIndex == MouseButton.WheelLeft )
            {
              scrollDelta.X *= -1;
            }

            // sliderValue += scrollDelta;
            // sliderValue = sliderValue.Clamp( 0, 1 );
            // SyncScroll();

            if ( Direction.Horizontal == direction )
            {
              scrollDelta.Y = 0;
            }
            else if ( Direction.Vertical == direction )
            {
              scrollDelta.X = 0;
            }

          
            nextValue = ( button.Position + scrollDelta ).Clamp( Vector2.Zero, GetButtonScrollRange() );

            // this.LogInfo( scrollDelta );

            var ui = this.FindParentThatIs<UI>();

            ui.onProcess.AddAction( UpdatePosition );
            ( button as UIStylePropertyContainer ).AddUISelectorFlag( UISelectorFlag.Scrolling, scrollID );
            ( button as UIStylePropertyContainerNode ).SetDirty();
            
          }
        };
      }

      if ( adjustButtonSizeToScrollContent )
      {
        scrollTarget.Resized += UpdateButtonSize;
        scrollContainer.Resized += UpdateButtonSize;

        UpdateButtonSize();
      }

      
    }

    void UpdateButtonSize()
    { 
      var value = new UINumber();
      var target = button as UIStylePropertyContainer;      

      if ( Direction.Vertical == direction )
      {
        value.value = Mathf.Min( 10, background.Size.Y - Mathf.Max( 10, scrollTarget.Size.Y - scrollContainer.Size.Y ) );
        target.SetUIStyleNumberProperty( UIStyleNumberProperty.Height, value );     
      }

      if ( Direction.Horizontal == direction )
      {
        value.value = Mathf.Min( 10, background.Size.X - Mathf.Max( 10, scrollTarget.Size.X - scrollContainer.Size.X ) );
        target.SetUIStyleNumberProperty( UIStyleNumberProperty.Width, value );   
      }
    }

    bool _dragging = false;
    bool _updatingPosition = false;

    UIDragging.UIDraggingCallbacks leftMouseCallbacks;
    UIDragging.UIDraggingCallbacks middleMouseCallbacks;


    public override void _Process( double delta )
    {
      if (
         leftMouseCallbacks == null || leftMouseCallbacks.notValid ||
         middleMouseCallbacks == null || middleMouseCallbacks.notValid 
      )
      {
        AddDraggingListener();
      }
    }

    void AddDraggingListener()
    {
      if ( button == null || scrollContainer == null )
      {
        return;
      }

      leftMouseCallbacks = UIDragging.OnLeftMouseButton( button,
        ( ev )=>
        {
          if ( ev.isStart )
          { 
            cachedButtonPosition = button.Position;
            smoothing.SetCurrent( cachedButtonPosition );

            _dragging = true;
            _updatingPosition = true;

            ev.ui.onProcess.AddAction( UpdatePosition );
            ( button as UIStylePropertyContainer ).AddUISelectorFlag( UISelectorFlag.Scrolling, scrollID );
          } 
          else if ( ev.isEnd )
          {
            _dragging = false;
          }

          var nextPosition = cachedButtonPosition + ev.distanceToStart;
          nextValue = nextPosition.Clamp( Vector2.Zero, GetButtonScrollRange() );                 
        
        }
      );

      middleMouseCallbacks = UIDragging.OnMiddleMouseButton( scrollContainer,
        ( ev )=>
        {
          if ( ev.isStart )
          { 
            cachedButtonPosition = button.Position;
            smoothing.SetCurrent( cachedButtonPosition );

            _dragging = true;
            _updatingPosition = true;

            ev.ui.onProcess.AddAction( UpdatePosition );
            ( button as UIStylePropertyContainer ).AddUISelectorFlag( UISelectorFlag.Scrolling, scrollID );
            ev.customOffset = Vector2.Zero;
          } 
          else if ( ev.isEnd )
          {
            _dragging = false;
          }

          ev.customOffset += ev.distanceToStart * 0.1f;
          var nextPosition = cachedButtonPosition + ev.customOffset;
          nextValue = nextPosition.Clamp( Vector2.Zero, GetButtonScrollRange() );     
          ev.customOffset = nextValue - cachedButtonPosition;            
        
        }
      );


    }

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

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

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

        value = nextValue;

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


      


      if ( Direction.Both == direction || Direction.Horizontal == direction )
      {
        var left = new UINumber();
        left.value = value.X;
        uiStyleContainer.SetUIStyleNumberProperty( UIStyleNumberProperty.Left, left );    

      }

      if ( Direction.Both == direction || Direction.Vertical == direction )
      {
        var top = new UINumber();
        top.value = value.Y;
        uiStyleContainer.SetUIStyleNumberProperty( UIStyleNumberProperty.Top, top );     
      }

      var range = background.Size - button.Size;
      sliderValue = button.Position / range;

      if ( scrollTarget != null && scrollContainer != null )
      {
        var scrollRange = scrollTarget.Size - scrollContainer.Size;

        var scrollOffset = scrollRange * sliderValue;

        var scrollTargetNode = scrollTarget as UIStylePropertyContainerNode;

        if ( Direction.Both == direction || Direction.Horizontal == direction )
        {
          var left = new UINumber();
          left.value = -scrollOffset.X;
          scrollTargetNode.SetUIStyleNumberProperty( UIStyleNumberProperty.Left, left ); 
        }

        if ( Direction.Both == direction || Direction.Vertical == direction )
        {
          var top = new UINumber();
          top.value = -scrollOffset.Y;
          scrollTargetNode.SetUIStyleNumberProperty( UIStyleNumberProperty.Top, top );  
                
        }
      }
      
    }

    Vector2 nextValue;

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

    Vector2 GetScrollRange()
    {
      return ( scrollTarget.Size - scrollContainer.Size ).Max( Vector2.Zero );
    }

    void SyncScroll()
    {

      if ( _dragging || _updatingPosition )
      {
        // this.LogInfo( "SyncScroll blocked" );
        return;
      }

      // this.LogInfo( "SyncScroll" );

      var uiStyleContainer = ( UIStylePropertyContainerNode ) button;
      var value = GetButtonScrollRange() * sliderValue;

      uiStyleContainer.SetDirty();
      
      if ( Direction.Both == direction || Direction.Horizontal == direction )
      {
        var left = new UINumber();
        left.value = value.X;
        uiStyleContainer.SetUIStyleNumberProperty( UIStyleNumberProperty.Left, left );      
      }

      if ( Direction.Both == direction || Direction.Vertical == direction )
      {
        var top = new UINumber();
        top.value = value.Y;
        uiStyleContainer.SetUIStyleNumberProperty( UIStyleNumberProperty.Top, top );      
      }

      if ( scrollTarget != null && scrollContainer != null )
      {
        var scrollRange = scrollTarget.Size - scrollContainer.Size;

        var scrollOffset = scrollRange * sliderValue;

        if ( Direction.Both == direction || Direction.Horizontal == direction )
        {
          var left = new UINumber();
          left.value = -scrollOffset.X;
          ( scrollTarget as UIStylePropertyContainer ).SetUIStyleNumberProperty( UIStyleNumberProperty.Left, left );      
        }

        if ( Direction.Both == direction || Direction.Vertical == direction )
        {
          var top = new UINumber();
          top.value = -scrollOffset.Y;
          ( scrollTarget as UIStylePropertyContainer ).SetUIStyleNumberProperty( UIStyleNumberProperty.Top, top );      
        }
      }
    }

    

    

  }
}