Editor/ChitChat/CustomWidgets/BaseDropdown.cs
using System;
using Sandbox;
using Editor;
using System.Collections.Generic;
using System.Linq;

namespace ChitChat.Editor;

public abstract class BaseDropdown : Widget
{
	public Action<int> onItemSelected;

	private int _currentSelected;
	private PopupWidget _menu;

	protected abstract IEnumerable<string> GetDropdownValues();

	public BaseDropdown(int firstSelected, Widget parent) : base(parent) 
	{ 
		_currentSelected = firstSelected;
	}

	public void UpdateSelected(int selected) => _currentSelected = selected;

	protected override void OnPaint()
	{
		var color = IsUnderMouse ? Theme.Blue : Theme.TextControl;
		var rect = LocalRect;

		rect = rect.Shrink(8, 0);

		Paint.SetBrushAndPen(Theme.ControlBackground);
		Paint.DrawRect(LocalRect, 2);
		
		Paint.SetPen(color);
		Paint.SetDefaultFont();

		IEnumerable<string> strings = GetDropdownValues();

		if(strings.Any() && _currentSelected <= strings.Count())
			Paint.DrawText(rect.Shrink(new Sandbox.UI.Margin(0, 0, 23, 0)), GetDropdownValues().Skip(_currentSelected).First(), TextFlag.LeftCenter);
		else
			Paint.DrawText(rect, "None", TextFlag.LeftCenter);

		Paint.SetPen(color);
		Paint.DrawIcon(rect, "Arrow_Drop_Down", 17, TextFlag.RightCenter);
	}

	protected override void OnMouseClick(MouseEvent e)
	{
		if (e.LeftMouseButton && !_menu.IsValid())
		{
			OpenMenu();
		}
	}

	protected override void OnDoubleClick(MouseEvent e)
	{
		// nothing
	}

	void OpenMenu()
	{
		string[] entries = GetDropdownValues().ToArray();
		if(_currentSelected > entries.Length - 1)
			_currentSelected = 0;
		
		if(entries.Length == 0) return;

		_menu = new PopupWidget(null);

		_menu.Layout = Layout.Column();
		_menu.Width = ScreenRect.Width;

		ScrollArea scroller = _menu.Layout.Add(new ScrollArea(this), 1);
		scroller.MaximumWidth = LocalRect.Width;
		scroller.HorizontalScrollbarMode = ScrollbarMode.Off;

		scroller.Canvas = new Widget(scroller)
		{
			Layout = Layout.Column(),
			VerticalSizeMode = SizeMode.CanGrow | SizeMode.Expand,
			MaximumWidth = entries.Length > 10 ? LocalRect.Width - 11 : LocalRect.Width - 1
		};
		scroller.Canvas.Layout.Alignment = TextFlag.LeftTop;

		for (int i = 0; i < entries.Length; i++)
		{
			var b = scroller.Canvas.Layout.Add(new MenuOption(entries[i], i, i == _currentSelected));
			b.SetSizeMode(SizeMode.Expand, SizeMode.Default);
			b.onMenuOptionSelected += OnMenuOptionSelected;
		}

		_menu.Position = ScreenRect.BottomLeft;
		_menu.Visible = true;
		_menu.AdjustSize();
		_menu.ConstrainToScreen();
		_menu.OnPaintOverride = PaintMenuBackground;
	}

	private void OnMenuOptionSelected(int index)
	{
		_currentSelected = index;

		onItemSelected?.Invoke(index);

		_menu.Update();
		_menu.Close();
	}

	bool PaintMenuBackground()
	{
		Paint.SetBrushAndPen(Theme.ControlBackground);
		Paint.DrawRect(Paint.LocalRect, 0);
		return true;
	}

	private class MenuOption : Widget
	{
		public Action<int> onMenuOptionSelected;

		private string _name;
		private int _index;
		private bool _selected;

		public MenuOption(string name, int index, bool selected) : base(null)
		{
			if(string.IsNullOrEmpty(name))
				_name = "Unnamed";
			else
				_name = name;

			_index = index;
			_selected = selected;

			MaximumHeight = 30;

			Layout = Layout.Row();
			Layout.Margin = new Sandbox.UI.Margin(30, 9, 8, 8);

			Layout.AddSpacingCell(8);
			Layout c = Layout.AddRow();
			Label title = c.Add(new Label(name));
			title.SetStyles("font-size: 12px; font-weight: bold; font-family: Poppins; color: white;");
		}

		protected override void OnMouseClick(MouseEvent e)
		{
			base.OnMouseClick(e);
			onMenuOptionSelected?.Invoke(_index);
		}

		protected override void OnPaint()
		{
			Rect iconRect = new Rect(LocalRect.TopLeft.x + 10, LocalRect.Center.y - 10, 20, 20);

			if(_selected)
				Paint.DrawIcon(iconRect, "check", 20);
			else
				Paint.DrawIcon(iconRect, "close", 20);

			if (Paint.HasMouseOver)
			{
				Paint.SetBrushAndPen(Theme.Blue.WithAlpha(0.3f));
				Paint.DrawRect(LocalRect.Shrink(2), 2);
			}
			else
			{
				if (_selected)
				{
					Paint.SetBrushAndPen(new Color(0.19f, 0.66f, 0.32f, 0.3f));
					Paint.DrawRect(LocalRect.Shrink(2), 2);
				}
				else
				{
					Paint.SetBrushAndPen(new Color(0.66f, 0.2f, 0.2f, 0.3f));
					Paint.DrawRect(LocalRect.Shrink(2), 2);
				}
			}
		}
	}
}