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

namespace Rokojori
{ 
  [Tool]
  [GlobalClass,Icon("res://addons/rokojori_action_library/Icons/UIRegion.svg")]
  public partial class UIRegion : Control, UIStylePropertyContainerNode, UIHolderControl
  {   

    [Export]
    public UIStyle parentStyle;

    [ExportGroup( "Layout" )]
    [Export]
    public UILayout layout;        

    [Export]
    public UINumber horizontalAlignment;
    [Export]
    public UINumber verticalAlignment;
    [Export]
    public UINumber verticalPlacement;

    [Export]
    public UINumber elementSpacing;
    [Export]
    public UINumber lineSpacing;

    
    [ExportGroup( "Size & Margins" )]
    [Export]
    public UINumber width;
    [Export]
    public UINumber height;


    [Export] 
    public UINumber margin;

    [Export] 
    public UINumber marginLeft;
    [Export] 
    public UINumber marginTop;
    [Export] 
    public UINumber marginRight;
    [Export] 
    public UINumber marginBottom;


    [ExportGroup( "Position" )]
    [Export]
    public UIPosition position;
    [Export]
    public UILineWrap lineWrap;
    [Export]
    public UINumber left;
    [Export]
    public UINumber top;
    [Export]
    public UINumber right;
    [Export]
    public UINumber bottom;

    [ExportGroup( "Font" )]
    [Export]
    public Font font;
    [Export]
    public UINumber fontSize;
    [Export]
    public UIColor fontColor;

    [Export]
    public UINumber outlineSize;
    [Export]
    public UIColor outlineColor;

    [Export]
    public UINumber shadowSize;
    [Export]
    public UIColor shadowColor;

    [Export]
    public UINumber shadowOffsetX;
    [Export]
    public UINumber shadowOffsetY;

    [ExportGroup( "Modulation" )]
    [Export]
    public UIColor modulationColor;
    [Export]
    public UIColor selfModulationColor;

    // public List<ActiveStyleTransition<UIColor,ColorPropertyName>> GetActiveShaderUIColorTransitions()
    // {
    //   return null;
    // }
  
    // public List<ActiveStyleTransition<UINumber,FloatPropertyName>> GetActiveShaderUINumberTransitions()
    // {
    //   return null;
    // }

    [ExportGroup("Transitions")]
    [Export]
    public TransitionSettingsAll transitionSettings;
    public TransitionSettingsAll GetTransitionSettingsAll()
    {
      return transitionSettings;
    }

    [Export]
    public UINumberTransition[] numberTransitions = new UINumberTransition[ 0 ];
    public UINumberTransition[] GetNumberTransitions()
    {
      return numberTransitions;
    }
    
    public List<ActiveStyleTransition<UINumber,UIStyleNumberPropertyAndName>> activeNumberTransitions = new List<ActiveStyleTransition<UINumber,UIStyleNumberPropertyAndName>>();
    public List<ActiveStyleTransition<UINumber,UIStyleNumberPropertyAndName>> GetActiveUINumberTransitions()
    {
      return activeNumberTransitions;
    }

    [Export]
    public UIColorTransition[] colorTransitions = new UIColorTransition[ 0 ];
    public UIColorTransition[] GetColorTransitions()
    {
      return colorTransitions;
    }
    
    public List<ActiveStyleTransition<UIColor,UIStyleColorPropertyAndName>> activeColorTransitions = new List<ActiveStyleTransition<UIColor,UIStyleColorPropertyAndName>>();
    public List<ActiveStyleTransition<UIColor,UIStyleColorPropertyAndName>> GetActiveUIColorTransitions()
    {
      return activeColorTransitions;
    }
    
    #if TOOLS
    [ExportGroup("Editor SceneSetup")]
    [Export]
    public UISettings uiSettings;

    [Export]
    public bool updateInEditor = false;

    [Export]
    public float fontZoom = 1f;

    

    [Export]
    public bool reassignUI;
    [ExportGroup("Editor SceneSetup/Read Only")]
    [Export]
    public float computedFontSize = 0f;

    #endif

    
    public UIStyle GetUIStyleParent()
    {
      return parentStyle;
    }

    public void SetUIStyleParent( UIStyle uiStyle )
    {
      parentStyle = uiStyle;
    }

    public UIPosition GetUIPosition()
    {
      return position;
    }

    public UILineWrap GetUILineWrap()
    {
      return lineWrap;
    }

    public UILayout GetUILayout()
    {
      return layout;
    }

    public ShaderUIColor[] GetShaderUIColors()
    {
      return null;
    }

    public ShaderUINumber[] GetShaderUINumbers()
    {
      return null;
    }

    public UICursor GetHoverCursor( UIStylePropertyContainer container )
    {
      return null;
    }
    
    public Font GetFont()
    {
      return font;
    }

    public Vector2 GetUISize()
    {
      return GetSize();
    }

    public UINumber GetUIStyleNumberProperty( UIStyleNumberProperty property, string shaderPropertyName, UIStylePropertyContainer source )
    {
      switch ( property )
      {
        case UIStyleNumberProperty.Left:   return left;
        case UIStyleNumberProperty.Right:  return right;
        case UIStyleNumberProperty.Top:    return top;
        case UIStyleNumberProperty.Bottom: return bottom;

        case UIStyleNumberProperty.Width:  return width;
        case UIStyleNumberProperty.Height: return height;
        
        case UIStyleNumberProperty.HorizontalAlignment: return horizontalAlignment;
        case UIStyleNumberProperty.VerticalAlignment: return verticalAlignment;
        case UIStyleNumberProperty.VerticalPlacement: return verticalPlacement;
        case UIStyleNumberProperty.ElementSpacing: return elementSpacing;
        case UIStyleNumberProperty.LineSpacing:    return lineSpacing;

        case UIStyleNumberProperty.Margin:       return margin;

        case UIStyleNumberProperty.MarginLeft:   return marginLeft;
        case UIStyleNumberProperty.MarginRight:  return marginRight;
        case UIStyleNumberProperty.MarginTop:    return marginTop;
        case UIStyleNumberProperty.MarginBottom: return marginBottom;

        case UIStyleNumberProperty.FontSize: return fontSize;
        case UIStyleNumberProperty.FontOutlineSize: return outlineSize;
        case UIStyleNumberProperty.FontShadowSize: return shadowSize;
        case UIStyleNumberProperty.FontShadowOffsetX: return shadowOffsetX;
        case UIStyleNumberProperty.FontShadowOffsetY: return shadowOffsetY;
        
      }

      return null;
    }

    public void SetUIStyleNumberProperty( UIStyleNumberProperty property, UINumber number )
    {
      switch ( property )
      {
        case UIStyleNumberProperty.Left:   { left = number; } break;
        case UIStyleNumberProperty.Right:  { right = number; } break;
        case UIStyleNumberProperty.Top:    { top = number; } break;
        case UIStyleNumberProperty.Bottom: { bottom = number; } break;

        case UIStyleNumberProperty.HorizontalAlignment: { horizontalAlignment = number; } break;
        case UIStyleNumberProperty.VerticalAlignment: { verticalAlignment = number; } break;
        case UIStyleNumberProperty.VerticalPlacement: { verticalPlacement = number; } break;
        case UIStyleNumberProperty.ElementSpacing: { elementSpacing = number; } break;
        case UIStyleNumberProperty.LineSpacing:    { lineSpacing = number; } break;


        case UIStyleNumberProperty.Width:  { width = number; } break;
        case UIStyleNumberProperty.Height: { height = number; } break;
        case UIStyleNumberProperty.Margin:       { margin = number; } break;

        case UIStyleNumberProperty.MarginLeft:   { marginLeft = number; } break;
        case UIStyleNumberProperty.MarginRight:  { marginRight = number; } break;
        case UIStyleNumberProperty.MarginTop:    { marginTop = number; } break;
        case UIStyleNumberProperty.MarginBottom: { marginBottom = number; } break;

        case UIStyleNumberProperty.FontSize: { fontSize = number; } break;
        case UIStyleNumberProperty.FontOutlineSize: { outlineSize = number; } break;
        case UIStyleNumberProperty.FontShadowSize: { shadowSize = number; } break;
        case UIStyleNumberProperty.FontShadowOffsetX: { shadowOffsetX = number; } break;
        case UIStyleNumberProperty.FontShadowOffsetY: { shadowOffsetY = number; } break;

      }

      this.SetLayoutDirtyFlag();
    }
    
    bool _isAnimated = false;
    int _isLayoutDirty = 3;

    public void ResetDirtyFlags()
    {
      _isAnimated = false;
      _isLayoutDirty = Mathf.Max( 0, _isLayoutDirty - 1 );
    }

    public void SetAnimatedFlag()
    {
      _isAnimated = true;
      this.SetDirty();
    }

    public void SetLayoutDirtyFlag()
    {
      _isLayoutDirty = 3;
      this.SetDirty();
    }


    public bool IsDirty()
    {
      return _isAnimated || _isLayoutDirty != 0 || this.HasActiveTransitions();
    }


    public UIColor GetUIStyleColorProperty( UIStyleColorProperty property, string shaderPropertyName, UIStylePropertyContainer source )
    {      
      switch ( property )
      {
        case UIStyleColorProperty.FontColor:            return fontColor;
        case UIStyleColorProperty.FontOutlineColor:     return outlineColor;
        case UIStyleColorProperty.FontShadowColor:      return shadowColor;
        case UIStyleColorProperty.ModulationColor:      return modulationColor;
        case UIStyleColorProperty.SelfModulationColor:  return selfModulationColor;
      } 

      return null;
    }

    string hoverID = IDGenerator.GenerateID();

    public override void _Ready()
    {
      MouseEntered += ()=>
      {
        AddUISelectorFlag( UISelectorFlag.Hover, hoverID );
        this.SetDirty();
        
      };

      MouseExited += ()=>
      {
        RemoveUISelectorFlag( UISelectorFlag.Hover, hoverID );
        this.SetDirty();
      };

    }

    int _uiAncestorDepth;

    public void ComputeUIAncestorDepth()
    {
      SetUIAncestorDepth( NodesWalker.Get().GetAncestorDistance( this, GetUI( false ) ) );
    }

    public void SetUIAncestorDepth( int depth )
    {
      _uiAncestorDepth = depth;
    }

    public int GetUIAncestorDepth()
    {
      return _uiAncestorDepth;
    }

    public override void _EnterTree()
    { 
      ComputeUIAncestorDepth();
    }

    public override void _ExitTree()
    {
      ui = null;
      _uiAncestorDepth = -1;
    }

    MapList<UISelectorFlag,string> _selectorFlagReferenceCounter = new MapList<UISelectorFlag, string>();

    public void AddUISelectorFlag( UISelectorFlag flag, string reference = "" )
    {
      SetSelectorFlagReference( flag, reference, true );
    }

    public void RemoveUISelectorFlag( UISelectorFlag flag, string reference = "" )
    {
      SetSelectorFlagReference( flag, reference, false );
    }

    protected override void Dispose( bool disposing)
    {
      _selectorFlagReferenceCounter.Clear();
    }

    void SetSelectorFlagReference( UISelectorFlag flag, string reference, bool enable )
    {
      if ( enable )
      {
        _selectorFlagReferenceCounter.AddIfNotPresent( flag, reference );
      }
      else
      {
        _selectorFlagReferenceCounter.Remove( flag, reference );
      }

      var numFlagsBefore = _selectorFlags.Count;
      _selectorFlags = _selectorFlagReferenceCounter.Keys.ToList();
      
      var changed = numFlagsBefore != _selectorFlags.Count;

      UISelector.UpdateParentUISelectorFlags( this );

      if ( changed )
      {
        this.SetDirty();
      }
    }

    List<UISelectorFlag> _selectorFlags = [];
    List<UISelectorFlag> _parentSelectorFlags = [];
    
    public List<UISelectorFlag> GetUISelectorFlags()
    {
      return _selectorFlags;
    }

    public List<UISelectorFlag> GetParentUISelectorFlags()
    {
      return _parentSelectorFlags;
    }

    public virtual void Layout()
    {
      var layout = UIStyle.Layout( this );

      switch ( layout )
      {
        case UILayout.___: 
        case UILayout.Flow_Left_Top: 
        {
          UIFlowLayout.Apply( this ); 
        }
        break;
      }
    }

    public Vector2 contentSize = Vector2.Zero;
    public Vector2 contentOffset = Vector2.Zero;

    UI ui;

    public void SetUI( UI ui, bool computeDepth = true )
    {
      this.ui = ui;

      if ( computeDepth )
      {
        ComputeUIAncestorDepth();
      }
    }

    public UI GetUI( bool computeDepth = true )
    {
      if ( this.ui != null )
      {
        return this.ui;
      }

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

      if ( ui == null )
      {
        
        _uiAncestorDepth =-1;
        this.LogInfo( "No UI in parents >", ui );

        return null; 
      }

      if ( computeDepth )
      {
        ComputeUIAncestorDepth();
      }

      return ui;
    }

  }
}